s4:torture/rpc: let rpc.netlogon.admin pass against windows 2012r2
[Samba.git] / lib / addns / dnssock.c
blob13649b5dd4c63dafe68bee64f304bf8311b6ab06
1 /*
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
9 ** under the LGPL
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/>.
25 #include "replace.h"
26 #include "dns.h"
27 #include <sys/time.h>
28 #include <unistd.h>
29 #include "system/select.h"
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,
40 TALLOC_CTX *mem_ctx,
41 struct dns_connection **result )
43 uint32_t ulAddress;
44 struct hostent *pHost;
45 struct sockaddr_in s_in;
46 struct dns_connection *conn;
47 int res;
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 ) {
55 TALLOC_FREE(conn);
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 );
62 if (conn->s == -1) {
63 TALLOC_FREE(conn);
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 do {
74 res = connect(conn->s, (struct sockaddr*)&s_in, sizeof( s_in ));
75 } while ((res == -1) && (errno == EINTR));
76 if (res == -1) {
77 TALLOC_FREE(conn);
78 return ERROR_DNS_CONNECTION_FAILED;
81 conn->hType = DNS_TCP;
83 *result = conn;
84 return ERROR_DNS_SUCCESS;
87 /********************************************************************
88 ********************************************************************/
90 static DNS_ERROR dns_udp_open( const char *nameserver,
91 TALLOC_CTX *mem_ctx,
92 struct dns_connection **result )
94 unsigned long ulAddress;
95 struct hostent *pHost;
96 struct sockaddr_in RecvAddr;
97 struct dns_connection *conn;
99 if (!(conn = talloc(NULL, struct dns_connection))) {
100 return ERROR_DNS_NO_MEMORY;
103 if ( (ulAddress = inet_addr( nameserver )) == INADDR_NONE ) {
104 if ( (pHost = gethostbyname( nameserver )) == NULL ) {
105 TALLOC_FREE(conn);
106 return ERROR_DNS_INVALID_NAME_SERVER;
108 memcpy( &ulAddress, pHost->h_addr, pHost->h_length );
111 /* Create a socket for sending data */
113 conn->s = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
114 if (conn->s == -1) {
115 TALLOC_FREE(conn);
116 return ERROR_DNS_CONNECTION_FAILED;
119 talloc_set_destructor(conn, destroy_dns_connection);
121 /* Set up the RecvAddr structure with the IP address of
122 the receiver (in this example case "123.456.789.1")
123 and the specified port number. */
125 ZERO_STRUCT(RecvAddr);
126 RecvAddr.sin_family = AF_INET;
127 RecvAddr.sin_port = htons( DNS_UDP_PORT );
128 RecvAddr.sin_addr.s_addr = ulAddress;
130 conn->hType = DNS_UDP;
131 memcpy( &conn->RecvAddr, &RecvAddr, sizeof( struct sockaddr_in ) );
133 *result = conn;
134 return ERROR_DNS_SUCCESS;
137 /********************************************************************
138 ********************************************************************/
140 DNS_ERROR dns_open_connection( const char *nameserver, int32_t dwType,
141 TALLOC_CTX *mem_ctx,
142 struct dns_connection **conn )
144 switch ( dwType ) {
145 case DNS_TCP:
146 return dns_tcp_open( nameserver, mem_ctx, conn );
147 case DNS_UDP:
148 return dns_udp_open( nameserver, mem_ctx, conn );
151 return ERROR_DNS_INVALID_PARAMETER;
154 static DNS_ERROR write_all(int fd, uint8_t *data, size_t len)
156 size_t total = 0;
158 while (total < len) {
160 ssize_t ret;
162 do {
163 ret = write(fd, data + total, len - total);
164 } while ((ret == -1) && (errno == EINTR));
166 if (ret <= 0) {
168 * EOF or error
170 return ERROR_DNS_SOCKET_ERROR;
173 total += ret;
176 return ERROR_DNS_SUCCESS;
179 static DNS_ERROR dns_send_tcp(struct dns_connection *conn,
180 const struct dns_buffer *buf)
182 uint16_t len = htons(buf->offset);
183 DNS_ERROR err;
185 err = write_all(conn->s, (uint8_t *)&len, sizeof(len));
186 if (!ERR_DNS_IS_OK(err)) return err;
188 return write_all(conn->s, buf->data, buf->offset);
191 static DNS_ERROR dns_send_udp(struct dns_connection *conn,
192 const struct dns_buffer *buf)
194 ssize_t ret;
196 do {
197 ret = sendto(conn->s, buf->data, buf->offset, 0,
198 (struct sockaddr *)&conn->RecvAddr,
199 sizeof(conn->RecvAddr));
200 } while ((ret == -1) && (errno == EINTR));
202 if (ret != buf->offset) {
203 return ERROR_DNS_SOCKET_ERROR;
206 return ERROR_DNS_SUCCESS;
209 DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf)
211 if (conn->hType == DNS_TCP) {
212 return dns_send_tcp(conn, buf);
215 if (conn->hType == DNS_UDP) {
216 return dns_send_udp(conn, buf);
219 return ERROR_DNS_INVALID_PARAMETER;
222 static DNS_ERROR read_all(int fd, uint8_t *data, size_t len)
224 size_t total = 0;
226 while (total < len) {
227 struct pollfd pfd;
228 ssize_t ret;
229 int fd_ready;
231 ZERO_STRUCT(pfd);
232 pfd.fd = fd;
233 pfd.events = POLLIN|POLLHUP;
235 fd_ready = poll(&pfd, 1, 10000);
236 if (fd_ready == -1) {
237 if (errno == EINTR) {
238 continue;
240 return ERROR_DNS_SOCKET_ERROR;
242 if ( fd_ready == 0 ) {
243 /* read timeout */
244 return ERROR_DNS_SOCKET_ERROR;
247 do {
248 ret = read(fd, data + total, len - total);
249 } while ((ret == -1) && (errno == EINTR));
251 if (ret <= 0) {
252 /* EOF or error */
253 return ERROR_DNS_SOCKET_ERROR;
256 total += ret;
259 return ERROR_DNS_SUCCESS;
262 static DNS_ERROR dns_receive_tcp(TALLOC_CTX *mem_ctx,
263 struct dns_connection *conn,
264 struct dns_buffer **presult)
266 struct dns_buffer *buf;
267 DNS_ERROR err;
268 uint16_t len;
270 if (!(buf = talloc_zero(mem_ctx, struct dns_buffer))) {
271 return ERROR_DNS_NO_MEMORY;
274 err = read_all(conn->s, (uint8_t *)&len, sizeof(len));
275 if (!ERR_DNS_IS_OK(err)) {
276 return err;
279 buf->size = ntohs(len);
281 if (buf->size) {
282 if (!(buf->data = talloc_array(buf, uint8_t, buf->size))) {
283 TALLOC_FREE(buf);
284 return ERROR_DNS_NO_MEMORY;
286 } else {
287 buf->data = NULL;
290 err = read_all(conn->s, buf->data, buf->size);
291 if (!ERR_DNS_IS_OK(err)) {
292 TALLOC_FREE(buf);
293 return err;
296 *presult = buf;
297 return ERROR_DNS_SUCCESS;
300 static DNS_ERROR dns_receive_udp(TALLOC_CTX *mem_ctx,
301 struct dns_connection *conn,
302 struct dns_buffer **presult)
304 struct dns_buffer *buf;
305 ssize_t received;
307 if (!(buf = talloc_zero(mem_ctx, struct dns_buffer))) {
308 return ERROR_DNS_NO_MEMORY;
312 * UDP based DNS can only be 512 bytes
315 if (!(buf->data = talloc_array(buf, uint8_t, 512))) {
316 TALLOC_FREE(buf);
317 return ERROR_DNS_NO_MEMORY;
320 do {
321 received = recv(conn->s, (void *)buf->data, 512, 0);
322 } while ((received == -1) && (errno == EINTR));
324 if (received == -1) {
325 TALLOC_FREE(buf);
326 return ERROR_DNS_SOCKET_ERROR;
329 if (received > 512) {
330 TALLOC_FREE(buf);
331 return ERROR_DNS_BAD_RESPONSE;
334 buf->size = received;
335 buf->offset = 0;
337 *presult = buf;
338 return ERROR_DNS_SUCCESS;
341 DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
342 struct dns_buffer **presult)
344 if (conn->hType == DNS_TCP) {
345 return dns_receive_tcp(mem_ctx, conn, presult);
348 if (conn->hType == DNS_UDP) {
349 return dns_receive_udp(mem_ctx, conn, presult);
352 return ERROR_DNS_INVALID_PARAMETER;
355 DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
356 const struct dns_request *req,
357 struct dns_request **resp)
359 struct dns_buffer *buf = NULL;
360 DNS_ERROR err;
362 err = dns_marshall_request(mem_ctx, req, &buf);
363 if (!ERR_DNS_IS_OK(err)) goto error;
365 err = dns_send(conn, buf);
366 if (!ERR_DNS_IS_OK(err)) goto error;
367 TALLOC_FREE(buf);
369 err = dns_receive(mem_ctx, conn, &buf);
370 if (!ERR_DNS_IS_OK(err)) goto error;
372 err = dns_unmarshall_request(mem_ctx, buf, resp);
374 error:
375 TALLOC_FREE(buf);
376 return err;
379 DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
380 struct dns_connection *conn,
381 struct dns_update_request *up_req,
382 struct dns_update_request **up_resp)
384 struct dns_request *resp;
385 DNS_ERROR err;
387 err = dns_transaction(mem_ctx, conn, dns_update2request(up_req),
388 &resp);
390 if (!ERR_DNS_IS_OK(err)) return err;
392 *up_resp = dns_request2update(resp);
393 return ERROR_DNS_SUCCESS;