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
30 /********************************************************************
31 ********************************************************************/
33 static DNS_ERROR
DNSTCPOpen( char *nameserver
, HANDLE
* phDNSServer
)
35 DNS_ERROR dwError
= ERROR_DNS_INVALID_PARAMETER
;
37 unsigned long ulAddress
;
38 struct hostent
*pHost
;
39 struct sockaddr_in s_in
;
40 DNS_CONNECTION_CONTEXT
*pDNSContext
= NULL
;
42 if ( (pDNSContext
= TALLOC_P( NULL
, DNS_CONNECTION_CONTEXT
)) == NULL
) {
43 return ERROR_DNS_NO_MEMORY
;
46 if ( (ulAddress
= inet_addr( nameserver
)) == INADDR_NONE
) {
47 if ( (pHost
= gethostbyname( nameserver
)) == NULL
) {
48 dwError
= ERROR_DNS_INVALID_NAME_SERVER
;
49 BAIL_ON_DNS_ERROR( dwError
);
51 memcpy( &ulAddress
, pHost
->h_addr
, pHost
->h_length
);
54 if ( (sockServer
= socket( PF_INET
, SOCK_STREAM
, 0 )) == INVALID_SOCKET
) {
55 dwError
= ERROR_DNS_NO_MEMORY
;
56 BAIL_ON_DNS_ERROR( dwError
);
59 s_in
.sin_family
= AF_INET
;
60 s_in
.sin_addr
.s_addr
= ulAddress
;
61 s_in
.sin_port
= htons( DNS_TCP_PORT
);
63 if ( (connect( sockServer
, (struct sockaddr
*)&s_in
, sizeof( s_in
))) == SOCKET_ERROR
) {
64 dwError
= ERROR_DNS_CONNECTION_FAILED
;
65 BAIL_ON_DNS_ERROR( dwError
);
68 pDNSContext
->s
= sockServer
;
69 pDNSContext
->hType
= DNS_TCP
;
71 *phDNSServer
= ( HANDLE
) pDNSContext
;
73 dwError
= ERROR_DNS_SUCCESS
;
78 TALLOC_FREE( pDNSContext
);
79 *phDNSServer
= ( HANDLE
) NULL
;
84 /********************************************************************
85 ********************************************************************/
87 static DNS_ERROR
DNSUDPOpen( char *nameserver
, HANDLE
* phDNSServer
)
89 DNS_ERROR dwError
= ERROR_DNS_INVALID_PARAMETER
;
91 unsigned long ulAddress
;
92 struct hostent
*pHost
;
93 struct sockaddr_in RecvAddr
;
94 DNS_CONNECTION_CONTEXT
*pDNSContext
= NULL
;
96 if ( (pDNSContext
= TALLOC_P( NULL
, DNS_CONNECTION_CONTEXT
)) == NULL
) {
97 return ERROR_DNS_NO_MEMORY
;
100 if ( (ulAddress
= inet_addr( nameserver
)) == INADDR_NONE
) {
101 if ( (pHost
= gethostbyname( nameserver
)) == NULL
) {
102 dwError
= ERROR_DNS_INVALID_NAME_SERVER
;
103 BAIL_ON_DNS_ERROR( dwError
);
105 memcpy( &ulAddress
, pHost
->h_addr
, pHost
->h_length
);
108 /* Create a socket for sending data */
110 SendSocket
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
112 /* Set up the RecvAddr structure with the IP address of
113 the receiver (in this example case "123.456.789.1")
114 and the specified port number. */
116 RecvAddr
.sin_family
= AF_INET
;
117 RecvAddr
.sin_port
= htons( DNS_UDP_PORT
);
118 RecvAddr
.sin_addr
.s_addr
= ulAddress
;
120 pDNSContext
->s
= SendSocket
;
121 pDNSContext
->hType
= DNS_UDP
;
122 memcpy( &pDNSContext
->RecvAddr
, &RecvAddr
, sizeof( struct sockaddr_in
) );
124 *phDNSServer
= ( HANDLE
) pDNSContext
;
126 dwError
= ERROR_DNS_SUCCESS
;
131 TALLOC_FREE( pDNSContext
);
132 *phDNSServer
= ( HANDLE
) NULL
;
137 /********************************************************************
138 ********************************************************************/
140 DNS_ERROR
DNSOpen( char *nameserver
, int32 dwType
, HANDLE
* phDNSServer
)
144 return DNSTCPOpen( nameserver
, phDNSServer
);
146 return DNSUDPOpen( nameserver
, phDNSServer
);
149 return ERROR_DNS_INVALID_PARAMETER
;
152 /********************************************************************
153 ********************************************************************/
155 static int32
DNSSendTCPRequest( HANDLE hDNSHandle
,
156 uint8
* pDNSSendBuffer
,
157 int32 dwBufferSize
, int32
* pdwBytesSent
)
160 int32 dwBytesSent
= 0;
161 DNS_CONNECTION_CONTEXT
*pDNSContext
= NULL
;
164 pDNSContext
= ( DNS_CONNECTION_CONTEXT
* ) hDNSHandle
;
166 dwBytesSent
= send( pDNSContext
->s
, pDNSSendBuffer
, dwBufferSize
, 0 );
167 if ( dwBytesSent
== SOCKET_ERROR
) {
168 dwError
= WSAGetLastError( );
169 BAIL_ON_ERROR( dwError
);
172 *pdwBytesSent
= dwBytesSent
;
181 /********************************************************************
182 ********************************************************************/
184 static int32
DNSSendUDPRequest( HANDLE hDNSHandle
,
185 uint8
* pDNSSendBuffer
,
186 int32 dwBufferSize
, int32
* pdwBytesSent
)
189 int32 dwBytesSent
= 0;
190 DNS_CONNECTION_CONTEXT
*pDNSContext
= NULL
;
192 pDNSContext
= ( DNS_CONNECTION_CONTEXT
* ) hDNSHandle
;
194 dwBytesSent
= sendto( pDNSContext
->s
,
198 ( struct sockaddr
* ) & pDNSContext
->RecvAddr
,
199 sizeof( pDNSContext
->RecvAddr
)
201 if ( dwBytesSent
== SOCKET_ERROR
) {
202 dwError
= WSAGetLastError( );
203 BAIL_ON_ERROR( dwError
);
205 *pdwBytesSent
= dwBytesSent
;
215 /********************************************************************
216 ********************************************************************/
218 static int32
DNSSelect( HANDLE hDNSHandle
)
223 int32 dwNumSockets
= 0;
224 DNS_CONNECTION_CONTEXT
*pDNSContext
= NULL
;
226 pDNSContext
= ( DNS_CONNECTION_CONTEXT
* ) hDNSHandle
;
228 FD_SET( pDNSContext
->s
, &rfds
);
232 dwNumSockets
= select( pDNSContext
->s
+ 1, &rfds
, NULL
, NULL
, &tv
);
233 if ( dwNumSockets
== SOCKET_ERROR
) {
234 dwError
= WSAGetLastError( );
235 BAIL_ON_ERROR( dwError
);
238 if ( !dwNumSockets
) {
242 dwError
= WSAETIMEDOUT
;
251 /********************************************************************
252 ********************************************************************/
254 static int32
DNSTCPReceiveBufferContext( HANDLE hDNSHandle
,
255 HANDLE hDNSRecvBuffer
, int32
* pdwBytesRead
)
259 int16 wBytesToRead
= 0;
260 int16 wnBytesToRead
= 0;
261 DNS_CONNECTION_CONTEXT
*pDNSContext
= NULL
;
262 DNS_RECEIVEBUFFER_CONTEXT
*pDNSRecvContext
= NULL
;
264 pDNSContext
= ( DNS_CONNECTION_CONTEXT
* ) hDNSHandle
;
265 pDNSRecvContext
= ( DNS_RECEIVEBUFFER_CONTEXT
* ) hDNSRecvBuffer
;
267 dwError
= DNSSelect( hDNSHandle
);
268 BAIL_ON_ERROR( dwError
);
270 dwRead
= recv( pDNSContext
->s
, ( char * ) &wnBytesToRead
,
271 sizeof( int16
), 0 );
272 if ( dwRead
== SOCKET_ERROR
) {
273 dwError
= WSAGetLastError( );
274 BAIL_ON_ERROR( dwError
);
277 wBytesToRead
= ntohs( wnBytesToRead
);
279 dwError
= DNSSelect( hDNSHandle
);
280 BAIL_ON_ERROR( dwError
);
282 dwRead
= recv( pDNSContext
->s
,
283 ( char * ) pDNSRecvContext
->pRecvBuffer
, wBytesToRead
,
285 if ( dwRead
== SOCKET_ERROR
) {
286 dwError
= WSAGetLastError( );
287 BAIL_ON_ERROR( dwError
);
290 pDNSRecvContext
->dwBytesRecvd
= dwRead
;
292 *pdwBytesRead
= ( int32
) dwRead
;
301 /********************************************************************
302 ********************************************************************/
304 static int32
DNSUDPReceiveBufferContext( HANDLE hDNSHandle
,
305 HANDLE hDNSRecvBuffer
, int32
* pdwBytesRead
)
309 DNS_CONNECTION_CONTEXT
*pDNSContext
= NULL
;
310 DNS_RECEIVEBUFFER_CONTEXT
*pDNSRecvContext
= NULL
;
312 pDNSContext
= ( DNS_CONNECTION_CONTEXT
* ) hDNSHandle
;
313 pDNSRecvContext
= ( DNS_RECEIVEBUFFER_CONTEXT
* ) hDNSRecvBuffer
;
315 dwError
= DNSSelect( hDNSHandle
);
316 BAIL_ON_ERROR( dwError
);
318 dwRead
= recv( pDNSContext
->s
,
319 ( char * ) pDNSRecvContext
->pRecvBuffer
, 512, 0 );
320 if ( dwRead
== SOCKET_ERROR
) {
321 dwError
= WSAGetLastError( );
322 BAIL_ON_ERROR( dwError
);
325 pDNSRecvContext
->dwBytesRecvd
= dwRead
;
327 *pdwBytesRead
= ( int32
) dwRead
;
334 /********************************************************************
335 ********************************************************************/
337 int32
DNSReceiveBufferContext( HANDLE hDNSHandle
,
338 HANDLE hDNSRecvBuffer
, int32
* pdwBytesRead
)
341 DNS_CONNECTION_CONTEXT
*pDNSContext
= NULL
;
343 pDNSContext
= ( DNS_CONNECTION_CONTEXT
* ) hDNSHandle
;
345 switch ( pDNSContext
->hType
) {
348 DNSTCPReceiveBufferContext( hDNSHandle
,
354 DNSUDPReceiveBufferContext( hDNSHandle
,
362 /********************************************************************
363 ********************************************************************/
365 int32
DNSCreateSendBuffer( HANDLE
* phDNSSendBuffer
)
368 DNS_SENDBUFFER_CONTEXT
*pDNSContext
= NULL
;
369 uint8
*pSendBuffer
= NULL
;
371 dwError
= DNSAllocateMemory( sizeof( DNS_SENDBUFFER_CONTEXT
),
372 ( void * ) &pDNSContext
);
373 BAIL_ON_ERROR( dwError
);
376 DNSAllocateMemory( SENDBUFFER_SIZE
,
377 ( void * ) &pSendBuffer
);
378 BAIL_ON_ERROR( dwError
);
380 pDNSContext
->pSendBuffer
= pSendBuffer
;
381 pDNSContext
->dwBufferSize
= SENDBUFFER_SIZE
;
383 /* We will offset into the buffer by 2 bytes
384 If we are doing a TCP write; we will fill in these
385 two bytes and send + 2 bytes
386 If we are doing a UDP write; we will start our send
387 +2 bytes and only send dwWritten; */
389 pDNSContext
->dwBufferOffset
+= 2;
391 *phDNSSendBuffer
= ( HANDLE
) pDNSContext
;
398 DNSFreeMemory( pSendBuffer
);
401 DNSFreeMemory( pDNSContext
);
403 *phDNSSendBuffer
= ( HANDLE
) NULL
;
409 /********************************************************************
410 ********************************************************************/
412 int32
DNSMarshallBuffer( HANDLE hDNSSendBuffer
,
413 uint8
* pDNSSendBuffer
,
414 int32 dwBufferSize
, int32
* pdwBytesWritten
)
418 DNS_SENDBUFFER_CONTEXT
*pDNSContext
= NULL
;
420 /* BugBug - we need to check for amount of space remaining in the
421 SendBuffer Context - if its insufficent, we want to realloc the
422 Buffer and copy the context; Right now the assumption is we have a big
425 pDNSContext
= ( DNS_SENDBUFFER_CONTEXT
* ) hDNSSendBuffer
;
427 pTemp
= pDNSContext
->pSendBuffer
+ pDNSContext
->dwBufferOffset
;
429 memcpy( pTemp
, pDNSSendBuffer
, dwBufferSize
);
431 pDNSContext
->dwBytesWritten
+= dwBufferSize
;
432 pDNSContext
->dwBufferOffset
+= dwBufferSize
;
434 *pdwBytesWritten
= dwBufferSize
;
439 /********************************************************************
440 ********************************************************************/
442 static int32
DNSTCPSendBufferContext( HANDLE hDNSServer
,
443 HANDLE hSendBuffer
, int32
* pdwBytesSent
)
445 DNS_SENDBUFFER_CONTEXT
*pSendBufferContext
= NULL
;
447 int16 wBytesWritten
= 0;
448 int16 wnBytesWritten
= 0;
450 pSendBufferContext
= ( DNS_SENDBUFFER_CONTEXT
* ) hSendBuffer
;
452 wBytesWritten
= ( int16
) pSendBufferContext
->dwBytesWritten
;
453 wnBytesWritten
= htons( wBytesWritten
);
455 memcpy( pSendBufferContext
->pSendBuffer
, &wnBytesWritten
,
458 dwError
= DNSSendTCPRequest( hDNSServer
,
459 pSendBufferContext
->pSendBuffer
,
460 pSendBufferContext
->dwBytesWritten
+ 2,
462 BAIL_ON_ERROR( dwError
);
469 /********************************************************************
470 ********************************************************************/
472 static int32
DNSUDPSendBufferContext( HANDLE hDNSServer
,
473 HANDLE hSendBuffer
, int32
* pdwBytesSent
)
475 DNS_SENDBUFFER_CONTEXT
*pSendBufferContext
= NULL
;
478 pSendBufferContext
= ( DNS_SENDBUFFER_CONTEXT
* ) hSendBuffer
;
480 /* Now remember to send 2 bytes ahead of pSendBuffer; because
481 we ignore the 2 bytes size field. */
483 dwError
= DNSSendUDPRequest( hDNSServer
,
484 pSendBufferContext
->pSendBuffer
+ 2,
485 pSendBufferContext
->dwBytesWritten
,
487 BAIL_ON_ERROR( dwError
);
494 /********************************************************************
495 ********************************************************************/
497 int32
DNSSendBufferContext( HANDLE hDNSServer
,
498 HANDLE hSendBuffer
, int32
* pdwBytesSent
)
500 DNS_CONNECTION_CONTEXT
*pDNSContext
= NULL
;
503 pDNSContext
= ( DNS_CONNECTION_CONTEXT
* ) hDNSServer
;
505 switch ( pDNSContext
->hType
) {
507 dwError
= DNSTCPSendBufferContext( hDNSServer
,
510 BAIL_ON_ERROR( dwError
);
514 dwError
= DNSUDPSendBufferContext( hDNSServer
,
517 BAIL_ON_ERROR( dwError
);
525 /********************************************************************
526 ********************************************************************/
528 int32
DNSDumpSendBufferContext( HANDLE hSendBuffer
)
530 DNS_SENDBUFFER_CONTEXT
*pSendBufferContext
= NULL
;
535 pSendBufferContext
= ( DNS_SENDBUFFER_CONTEXT
* ) hSendBuffer
;
537 printf( "Buffer Size is: %d\n", pSendBufferContext
->dwBytesWritten
);
538 while ( i
< pSendBufferContext
->dwBytesWritten
) {
539 if ( ( i
/ 16 ) > dwCurLine
) {
543 if ( ( i
% 8 ) == 0 ) {
546 printf( "%.2x ", pSendBufferContext
->pSendBuffer
[i
] );
552 /********************************************************************
553 ********************************************************************/
555 int32
DNSDumpRecvBufferContext( HANDLE hRecvBuffer
)
557 DNS_RECEIVEBUFFER_CONTEXT
*pRecvBufferContext
= NULL
;
562 pRecvBufferContext
= ( DNS_RECEIVEBUFFER_CONTEXT
* ) hRecvBuffer
;
565 printf( "Buffer Size is: %d\n", pRecvBufferContext
->dwBytesRecvd
);
567 while ( i
< pRecvBufferContext
->dwBytesRecvd
) {
568 if ( ( i
/ 16 ) > dwCurLine
) {
572 if ( ( i
% 8 ) == 0 ) {
575 printf( "%.2x ", pRecvBufferContext
->pRecvBuffer
[i
] );
581 /********************************************************************
582 ********************************************************************/
584 int32
DNSCreateReceiveBuffer( HANDLE
* phDNSRecvBuffer
)
587 DNS_RECEIVEBUFFER_CONTEXT
*pDNSContext
= NULL
;
588 uint8
*pRecvBuffer
= NULL
;
590 dwError
= DNSAllocateMemory( sizeof( DNS_RECEIVEBUFFER_CONTEXT
),
591 ( void * ) &pDNSContext
);
592 BAIL_ON_ERROR( dwError
);
595 DNSAllocateMemory( RECVBUFFER_SIZE
,
596 ( void * ) &pRecvBuffer
);
597 BAIL_ON_ERROR( dwError
);
599 pDNSContext
->pRecvBuffer
= pRecvBuffer
;
600 pDNSContext
->dwBufferSize
= RECVBUFFER_SIZE
;
602 *phDNSRecvBuffer
= ( HANDLE
) pDNSContext
;
609 DNSFreeMemory( pRecvBuffer
);
612 DNSFreeMemory( pDNSContext
);
614 *phDNSRecvBuffer
= ( HANDLE
) NULL
;
619 /********************************************************************
620 ********************************************************************/
622 int32
DNSUnmarshallBuffer( HANDLE hDNSRecvBuffer
,
623 uint8
* pDNSRecvBuffer
,
624 int32 dwBufferSize
, int32
* pdwBytesRead
)
628 DNS_RECEIVEBUFFER_CONTEXT
*pDNSContext
= NULL
;
630 /* BugBug - we need to check for amount of space remaining in the
631 SendBuffer Context - if its insufficent, we want to realloc the
632 Buffer and copy the context; Right now the assumption is we have a big
635 pDNSContext
= ( DNS_RECEIVEBUFFER_CONTEXT
* ) hDNSRecvBuffer
;
637 pTemp
= pDNSContext
->pRecvBuffer
+ pDNSContext
->dwBytesRead
;
639 memcpy( pDNSRecvBuffer
, pTemp
, dwBufferSize
);
641 pDNSContext
->dwBytesRead
+= dwBufferSize
;
643 *pdwBytesRead
= dwBufferSize
;
648 /********************************************************************
649 ********************************************************************/
651 int32
DNSUnmarshallDomainNameAtOffset( HANDLE hRecvBuffer
,
653 DNS_DOMAIN_NAME
** ppDomainName
)
656 DNS_DOMAIN_LABEL
*pLabel
= NULL
;
657 DNS_DOMAIN_LABEL
*pLabelList
= NULL
;
658 DNS_DOMAIN_NAME
*pDomainName
= NULL
;
659 char *pszLabel
= NULL
;
663 DNS_RECEIVEBUFFER_CONTEXT
*pRecvContext
= NULL
;
665 pRecvContext
= ( DNS_RECEIVEBUFFER_CONTEXT
* ) hRecvBuffer
;
670 memcpy( &uLen
, pRecvContext
->pRecvBuffer
+ dwCurrent
,
678 memset( szLabel
, 0, 65 );
679 memcpy( szLabel
, pRecvContext
->pRecvBuffer
+ dwCurrent
,
683 dwError
= DNSAllocateString( szLabel
, &pszLabel
);
684 BAIL_ON_ERROR( dwError
);
687 DNSAllocateMemory( sizeof( DNS_DOMAIN_LABEL
),
688 ( void * ) &pLabel
);
689 BAIL_ON_ERROR( dwError
);
691 pLabel
->pszLabel
= pszLabel
;
692 dwError
= DNSAppendLabel( pLabelList
, pLabel
, &pLabelList
);
693 BAIL_ON_ERROR( dwError
);
697 DNSAllocateMemory( sizeof( DNS_DOMAIN_NAME
),
698 ( void * ) &pDomainName
);
699 BAIL_ON_ERROR( dwError
);
700 pDomainName
->pLabelList
= pLabelList
;
702 *ppDomainName
= pDomainName
;
708 *ppDomainName
= NULL
;
712 /********************************************************************
713 ********************************************************************/
715 int32
DNSReceiveBufferMoveBackIndex( HANDLE hRecvBuffer
, int16 wOffset
)
718 DNS_RECEIVEBUFFER_CONTEXT
*pDNSContext
= NULL
;
720 pDNSContext
= ( DNS_RECEIVEBUFFER_CONTEXT
* ) hRecvBuffer
;
721 pDNSContext
->dwBytesRead
-= wOffset
;
726 /********************************************************************
727 ********************************************************************/
729 void DNSFreeSendBufferContext( HANDLE hSendBuffer
)
731 DNS_SENDBUFFER_CONTEXT
*pSendBufferContext
= NULL
;
733 pSendBufferContext
= ( DNS_SENDBUFFER_CONTEXT
* ) hSendBuffer
;
735 if ( pSendBufferContext
&& pSendBufferContext
->pSendBuffer
) {
736 DNSFreeMemory( pSendBufferContext
->pSendBuffer
);
738 if ( pSendBufferContext
) {
739 DNSFreeMemory( pSendBufferContext
);
743 /********************************************************************
744 ********************************************************************/
746 int32
DNSGetSendBufferContextSize( HANDLE hSendBuffer
)
748 DNS_SENDBUFFER_CONTEXT
*pSendBufferContext
= NULL
;
750 pSendBufferContext
= ( DNS_SENDBUFFER_CONTEXT
* ) hSendBuffer
;
752 return ( pSendBufferContext
->dwBytesWritten
);
756 /********************************************************************
757 ********************************************************************/
759 uint8
*DNSGetSendBufferContextBuffer( HANDLE hSendBuffer
)
761 DNS_SENDBUFFER_CONTEXT
*pSendBufferContext
= NULL
;
763 pSendBufferContext
= ( DNS_SENDBUFFER_CONTEXT
* ) hSendBuffer
;
765 return ( pSendBufferContext
->pSendBuffer
);