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