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
29 /********************************************************************
30 ********************************************************************/
32 static DNS_ERROR
DNSTCPOpen( char *nameserver
, HANDLE
* phDNSServer
)
34 DNS_ERROR dwError
= ERROR_DNS_INVALID_PARAMETER
;
36 unsigned long ulAddress
;
37 struct hostent
*pHost
;
38 struct sockaddr_in s_in
;
39 DNS_CONNECTION_CONTEXT
*pDNSContext
= NULL
;
41 if ( (pDNSContext
= TALLOC_P( NULL
, DNS_CONNECTION_CONTEXT
)) == NULL
) {
42 return ERROR_DNS_NO_MEMORY
;
45 if ( (ulAddress
= inet_addr( nameserver
)) == INADDR_NONE
) {
46 if ( (pHost
= gethostbyname( nameserver
)) == NULL
) {
47 dwError
= ERROR_DNS_INVALID_NAME_SERVER
;
48 BAIL_ON_DNS_ERROR( dwError
);
50 memcpy( &ulAddress
, pHost
->h_addr
, pHost
->h_length
);
53 if ( (sockServer
= socket( PF_INET
, SOCK_STREAM
, 0 )) == INVALID_SOCKET
) {
54 dwError
= ERROR_DNS_NO_MEMORY
;
55 BAIL_ON_DNS_ERROR( dwError
);
58 s_in
.sin_family
= AF_INET
;
59 s_in
.sin_addr
.s_addr
= ulAddress
;
60 s_in
.sin_port
= htons( DNS_TCP_PORT
);
62 if ( (connect( sockServer
, (struct sockaddr
*)&s_in
, sizeof( s_in
))) == SOCKET_ERROR
) {
63 dwError
= ERROR_DNS_CONNECTION_FAILED
;
64 BAIL_ON_DNS_ERROR( dwError
);
67 pDNSContext
->s
= sockServer
;
68 pDNSContext
->hType
= DNS_TCP
;
70 *phDNSServer
= ( HANDLE
) pDNSContext
;
72 dwError
= ERROR_DNS_SUCCESS
;
77 TALLOC_FREE( pDNSContext
);
78 *phDNSServer
= ( HANDLE
) NULL
;
83 /********************************************************************
84 ********************************************************************/
86 static DNS_ERROR
DNSUDPOpen( char *nameserver
, HANDLE
* phDNSServer
)
88 DNS_ERROR dwError
= ERROR_DNS_INVALID_PARAMETER
;
90 unsigned long ulAddress
;
91 struct hostent
*pHost
;
92 struct sockaddr_in RecvAddr
;
93 DNS_CONNECTION_CONTEXT
*pDNSContext
= NULL
;
95 if ( (pDNSContext
= TALLOC_P( NULL
, DNS_CONNECTION_CONTEXT
)) == NULL
) {
96 return ERROR_DNS_NO_MEMORY
;
99 if ( (ulAddress
= inet_addr( nameserver
)) == INADDR_NONE
) {
100 if ( (pHost
= gethostbyname( nameserver
)) == NULL
) {
101 dwError
= ERROR_DNS_INVALID_NAME_SERVER
;
102 BAIL_ON_DNS_ERROR( dwError
);
104 memcpy( &ulAddress
, pHost
->h_addr
, pHost
->h_length
);
107 /* Create a socket for sending data */
109 SendSocket
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
111 /* Set up the RecvAddr structure with the IP address of
112 the receiver (in this example case "123.456.789.1")
113 and the specified port number. */
115 RecvAddr
.sin_family
= AF_INET
;
116 RecvAddr
.sin_port
= htons( DNS_UDP_PORT
);
117 RecvAddr
.sin_addr
.s_addr
= ulAddress
;
119 pDNSContext
->s
= SendSocket
;
120 pDNSContext
->hType
= DNS_UDP
;
121 memcpy( &pDNSContext
->RecvAddr
, &RecvAddr
, sizeof( struct sockaddr_in
) );
123 *phDNSServer
= ( HANDLE
) pDNSContext
;
125 dwError
= ERROR_DNS_SUCCESS
;
130 TALLOC_FREE( pDNSContext
);
131 *phDNSServer
= ( HANDLE
) NULL
;
136 /********************************************************************
137 ********************************************************************/
139 DNS_ERROR
DNSOpen( char *nameserver
, int32 dwType
, HANDLE
* phDNSServer
)
143 return DNSTCPOpen( nameserver
, phDNSServer
);
145 return DNSUDPOpen( nameserver
, phDNSServer
);
148 return ERROR_DNS_INVALID_PARAMETER
;
151 /********************************************************************
152 ********************************************************************/
154 static int32
DNSSendTCPRequest( HANDLE hDNSHandle
,
155 uint8
* pDNSSendBuffer
,
156 int32 dwBufferSize
, int32
* pdwBytesSent
)
159 int32 dwBytesSent
= 0;
160 DNS_CONNECTION_CONTEXT
*pDNSContext
= NULL
;
163 pDNSContext
= ( DNS_CONNECTION_CONTEXT
* ) hDNSHandle
;
165 dwBytesSent
= send( pDNSContext
->s
, pDNSSendBuffer
, dwBufferSize
, 0 );
166 if ( dwBytesSent
== SOCKET_ERROR
) {
167 dwError
= WSAGetLastError( );
168 BAIL_ON_ERROR( dwError
);
171 *pdwBytesSent
= dwBytesSent
;
180 /********************************************************************
181 ********************************************************************/
183 static int32
DNSSendUDPRequest( HANDLE hDNSHandle
,
184 uint8
* pDNSSendBuffer
,
185 int32 dwBufferSize
, int32
* pdwBytesSent
)
188 int32 dwBytesSent
= 0;
189 DNS_CONNECTION_CONTEXT
*pDNSContext
= NULL
;
191 pDNSContext
= ( DNS_CONNECTION_CONTEXT
* ) hDNSHandle
;
193 dwBytesSent
= sendto( pDNSContext
->s
,
197 ( struct sockaddr
* ) & pDNSContext
->RecvAddr
,
198 sizeof( pDNSContext
->RecvAddr
)
200 if ( dwBytesSent
== SOCKET_ERROR
) {
201 dwError
= WSAGetLastError( );
202 BAIL_ON_ERROR( dwError
);
204 *pdwBytesSent
= dwBytesSent
;
214 /********************************************************************
215 ********************************************************************/
217 static int32
DNSSelect( HANDLE hDNSHandle
)
222 int32 dwNumSockets
= 0;
223 DNS_CONNECTION_CONTEXT
*pDNSContext
= NULL
;
225 pDNSContext
= ( DNS_CONNECTION_CONTEXT
* ) hDNSHandle
;
227 FD_SET( pDNSContext
->s
, &rfds
);
231 dwNumSockets
= select( pDNSContext
->s
+ 1, &rfds
, NULL
, NULL
, &tv
);
232 if ( dwNumSockets
== SOCKET_ERROR
) {
233 dwError
= WSAGetLastError( );
234 BAIL_ON_ERROR( dwError
);
237 if ( !dwNumSockets
) {
241 dwError
= WSAETIMEDOUT
;
250 /********************************************************************
251 ********************************************************************/
253 static int32
DNSTCPReceiveBufferContext( HANDLE hDNSHandle
,
254 HANDLE hDNSRecvBuffer
, int32
* pdwBytesRead
)
258 int16 wBytesToRead
= 0;
259 int16 wnBytesToRead
= 0;
260 DNS_CONNECTION_CONTEXT
*pDNSContext
= NULL
;
261 DNS_RECEIVEBUFFER_CONTEXT
*pDNSRecvContext
= NULL
;
263 pDNSContext
= ( DNS_CONNECTION_CONTEXT
* ) hDNSHandle
;
264 pDNSRecvContext
= ( DNS_RECEIVEBUFFER_CONTEXT
* ) hDNSRecvBuffer
;
266 dwError
= DNSSelect( hDNSHandle
);
267 BAIL_ON_ERROR( dwError
);
269 dwRead
= recv( pDNSContext
->s
, ( char * ) &wnBytesToRead
,
270 sizeof( int16
), 0 );
271 if ( dwRead
== SOCKET_ERROR
) {
272 dwError
= WSAGetLastError( );
273 BAIL_ON_ERROR( dwError
);
276 wBytesToRead
= ntohs( wnBytesToRead
);
278 dwError
= DNSSelect( hDNSHandle
);
279 BAIL_ON_ERROR( dwError
);
281 dwRead
= recv( pDNSContext
->s
,
282 ( char * ) pDNSRecvContext
->pRecvBuffer
, wBytesToRead
,
284 if ( dwRead
== SOCKET_ERROR
) {
285 dwError
= WSAGetLastError( );
286 BAIL_ON_ERROR( dwError
);
289 pDNSRecvContext
->dwBytesRecvd
= dwRead
;
291 *pdwBytesRead
= ( int32
) dwRead
;
300 /********************************************************************
301 ********************************************************************/
303 static int32
DNSUDPReceiveBufferContext( HANDLE hDNSHandle
,
304 HANDLE hDNSRecvBuffer
, int32
* pdwBytesRead
)
308 DNS_CONNECTION_CONTEXT
*pDNSContext
= NULL
;
309 DNS_RECEIVEBUFFER_CONTEXT
*pDNSRecvContext
= NULL
;
311 pDNSContext
= ( DNS_CONNECTION_CONTEXT
* ) hDNSHandle
;
312 pDNSRecvContext
= ( DNS_RECEIVEBUFFER_CONTEXT
* ) hDNSRecvBuffer
;
314 dwError
= DNSSelect( hDNSHandle
);
315 BAIL_ON_ERROR( dwError
);
317 dwRead
= recv( pDNSContext
->s
,
318 ( char * ) pDNSRecvContext
->pRecvBuffer
, 512, 0 );
319 if ( dwRead
== SOCKET_ERROR
) {
320 dwError
= WSAGetLastError( );
321 BAIL_ON_ERROR( dwError
);
324 pDNSRecvContext
->dwBytesRecvd
= dwRead
;
326 *pdwBytesRead
= ( int32
) dwRead
;
333 /********************************************************************
334 ********************************************************************/
336 int32
DNSReceiveBufferContext( HANDLE hDNSHandle
,
337 HANDLE hDNSRecvBuffer
, int32
* pdwBytesRead
)
340 DNS_CONNECTION_CONTEXT
*pDNSContext
= NULL
;
342 pDNSContext
= ( DNS_CONNECTION_CONTEXT
* ) hDNSHandle
;
344 switch ( pDNSContext
->hType
) {
347 DNSTCPReceiveBufferContext( hDNSHandle
,
353 DNSUDPReceiveBufferContext( hDNSHandle
,
361 /********************************************************************
362 ********************************************************************/
364 int32
DNSCreateSendBuffer( HANDLE
* phDNSSendBuffer
)
367 DNS_SENDBUFFER_CONTEXT
*pDNSContext
= NULL
;
368 uint8
*pSendBuffer
= NULL
;
370 dwError
= DNSAllocateMemory( sizeof( DNS_SENDBUFFER_CONTEXT
),
371 ( void * ) &pDNSContext
);
372 BAIL_ON_ERROR( dwError
);
375 DNSAllocateMemory( SENDBUFFER_SIZE
,
376 ( void * ) &pSendBuffer
);
377 BAIL_ON_ERROR( dwError
);
379 pDNSContext
->pSendBuffer
= pSendBuffer
;
380 pDNSContext
->dwBufferSize
= SENDBUFFER_SIZE
;
382 /* We will offset into the buffer by 2 bytes
383 If we are doing a TCP write; we will fill in these
384 two bytes and send + 2 bytes
385 If we are doing a UDP write; we will start our send
386 +2 bytes and only send dwWritten; */
388 pDNSContext
->dwBufferOffset
+= 2;
390 *phDNSSendBuffer
= ( HANDLE
) pDNSContext
;
397 DNSFreeMemory( pSendBuffer
);
400 DNSFreeMemory( pDNSContext
);
402 *phDNSSendBuffer
= ( HANDLE
) NULL
;
408 /********************************************************************
409 ********************************************************************/
411 int32
DNSMarshallBuffer( HANDLE hDNSSendBuffer
,
412 uint8
* pDNSSendBuffer
,
413 int32 dwBufferSize
, int32
* pdwBytesWritten
)
417 DNS_SENDBUFFER_CONTEXT
*pDNSContext
= NULL
;
419 /* BugBug - we need to check for amount of space remaining in the
420 SendBuffer Context - if its insufficent, we want to realloc the
421 Buffer and copy the context; Right now the assumption is we have a big
424 pDNSContext
= ( DNS_SENDBUFFER_CONTEXT
* ) hDNSSendBuffer
;
426 pTemp
= pDNSContext
->pSendBuffer
+ pDNSContext
->dwBufferOffset
;
428 memcpy( pTemp
, pDNSSendBuffer
, dwBufferSize
);
430 pDNSContext
->dwBytesWritten
+= dwBufferSize
;
431 pDNSContext
->dwBufferOffset
+= dwBufferSize
;
433 *pdwBytesWritten
= dwBufferSize
;
438 /********************************************************************
439 ********************************************************************/
441 static int32
DNSTCPSendBufferContext( HANDLE hDNSServer
,
442 HANDLE hSendBuffer
, int32
* pdwBytesSent
)
444 DNS_SENDBUFFER_CONTEXT
*pSendBufferContext
= NULL
;
446 int16 wBytesWritten
= 0;
447 int16 wnBytesWritten
= 0;
449 pSendBufferContext
= ( DNS_SENDBUFFER_CONTEXT
* ) hSendBuffer
;
451 wBytesWritten
= ( int16
) pSendBufferContext
->dwBytesWritten
;
452 wnBytesWritten
= htons( wBytesWritten
);
454 memcpy( pSendBufferContext
->pSendBuffer
, &wnBytesWritten
,
457 dwError
= DNSSendTCPRequest( hDNSServer
,
458 pSendBufferContext
->pSendBuffer
,
459 pSendBufferContext
->dwBytesWritten
+ 2,
461 BAIL_ON_ERROR( dwError
);
468 /********************************************************************
469 ********************************************************************/
471 static int32
DNSUDPSendBufferContext( HANDLE hDNSServer
,
472 HANDLE hSendBuffer
, int32
* pdwBytesSent
)
474 DNS_SENDBUFFER_CONTEXT
*pSendBufferContext
= NULL
;
477 pSendBufferContext
= ( DNS_SENDBUFFER_CONTEXT
* ) hSendBuffer
;
479 /* Now remember to send 2 bytes ahead of pSendBuffer; because
480 we ignore the 2 bytes size field. */
482 dwError
= DNSSendUDPRequest( hDNSServer
,
483 pSendBufferContext
->pSendBuffer
+ 2,
484 pSendBufferContext
->dwBytesWritten
,
486 BAIL_ON_ERROR( dwError
);
493 /********************************************************************
494 ********************************************************************/
496 int32
DNSSendBufferContext( HANDLE hDNSServer
,
497 HANDLE hSendBuffer
, int32
* pdwBytesSent
)
499 DNS_CONNECTION_CONTEXT
*pDNSContext
= NULL
;
502 pDNSContext
= ( DNS_CONNECTION_CONTEXT
* ) hDNSServer
;
504 switch ( pDNSContext
->hType
) {
506 dwError
= DNSTCPSendBufferContext( hDNSServer
,
509 BAIL_ON_ERROR( dwError
);
513 dwError
= DNSUDPSendBufferContext( hDNSServer
,
516 BAIL_ON_ERROR( dwError
);
524 /********************************************************************
525 ********************************************************************/
527 int32
DNSDumpSendBufferContext( HANDLE hSendBuffer
)
529 DNS_SENDBUFFER_CONTEXT
*pSendBufferContext
= NULL
;
534 pSendBufferContext
= ( DNS_SENDBUFFER_CONTEXT
* ) hSendBuffer
;
536 printf( "Buffer Size is: %d\n", pSendBufferContext
->dwBytesWritten
);
537 while ( i
< pSendBufferContext
->dwBytesWritten
) {
538 if ( ( i
/ 16 ) > dwCurLine
) {
542 if ( ( i
% 8 ) == 0 ) {
545 printf( "%.2x ", pSendBufferContext
->pSendBuffer
[i
] );
551 /********************************************************************
552 ********************************************************************/
554 int32
DNSDumpRecvBufferContext( HANDLE hRecvBuffer
)
556 DNS_RECEIVEBUFFER_CONTEXT
*pRecvBufferContext
= NULL
;
561 pRecvBufferContext
= ( DNS_RECEIVEBUFFER_CONTEXT
* ) hRecvBuffer
;
564 printf( "Buffer Size is: %d\n", pRecvBufferContext
->dwBytesRecvd
);
566 while ( i
< pRecvBufferContext
->dwBytesRecvd
) {
567 if ( ( i
/ 16 ) > dwCurLine
) {
571 if ( ( i
% 8 ) == 0 ) {
574 printf( "%.2x ", pRecvBufferContext
->pRecvBuffer
[i
] );
580 /********************************************************************
581 ********************************************************************/
583 int32
DNSCreateReceiveBuffer( HANDLE
* phDNSRecvBuffer
)
586 DNS_RECEIVEBUFFER_CONTEXT
*pDNSContext
= NULL
;
587 uint8
*pRecvBuffer
= NULL
;
589 dwError
= DNSAllocateMemory( sizeof( DNS_RECEIVEBUFFER_CONTEXT
),
590 ( void * ) &pDNSContext
);
591 BAIL_ON_ERROR( dwError
);
594 DNSAllocateMemory( RECVBUFFER_SIZE
,
595 ( void * ) &pRecvBuffer
);
596 BAIL_ON_ERROR( dwError
);
598 pDNSContext
->pRecvBuffer
= pRecvBuffer
;
599 pDNSContext
->dwBufferSize
= RECVBUFFER_SIZE
;
601 *phDNSRecvBuffer
= ( HANDLE
) pDNSContext
;
608 DNSFreeMemory( pRecvBuffer
);
611 DNSFreeMemory( pDNSContext
);
613 *phDNSRecvBuffer
= ( HANDLE
) NULL
;
618 /********************************************************************
619 ********************************************************************/
621 int32
DNSUnmarshallBuffer( HANDLE hDNSRecvBuffer
,
622 uint8
* pDNSRecvBuffer
,
623 int32 dwBufferSize
, int32
* pdwBytesRead
)
627 DNS_RECEIVEBUFFER_CONTEXT
*pDNSContext
= NULL
;
629 /* BugBug - we need to check for amount of space remaining in the
630 SendBuffer Context - if its insufficent, we want to realloc the
631 Buffer and copy the context; Right now the assumption is we have a big
634 pDNSContext
= ( DNS_RECEIVEBUFFER_CONTEXT
* ) hDNSRecvBuffer
;
636 pTemp
= pDNSContext
->pRecvBuffer
+ pDNSContext
->dwBytesRead
;
638 memcpy( pDNSRecvBuffer
, pTemp
, dwBufferSize
);
640 pDNSContext
->dwBytesRead
+= dwBufferSize
;
642 *pdwBytesRead
= dwBufferSize
;
647 /********************************************************************
648 ********************************************************************/
650 int32
DNSUnmarshallDomainNameAtOffset( HANDLE hRecvBuffer
,
652 DNS_DOMAIN_NAME
** ppDomainName
)
655 DNS_DOMAIN_LABEL
*pLabel
= NULL
;
656 DNS_DOMAIN_LABEL
*pLabelList
= NULL
;
657 DNS_DOMAIN_NAME
*pDomainName
= NULL
;
658 char *pszLabel
= NULL
;
662 DNS_RECEIVEBUFFER_CONTEXT
*pRecvContext
= NULL
;
664 pRecvContext
= ( DNS_RECEIVEBUFFER_CONTEXT
* ) hRecvBuffer
;
669 memcpy( &uLen
, pRecvContext
->pRecvBuffer
+ dwCurrent
,
677 memset( szLabel
, 0, 65 );
678 memcpy( szLabel
, pRecvContext
->pRecvBuffer
+ dwCurrent
,
682 dwError
= DNSAllocateString( szLabel
, &pszLabel
);
683 BAIL_ON_ERROR( dwError
);
686 DNSAllocateMemory( sizeof( DNS_DOMAIN_LABEL
),
687 ( void * ) &pLabel
);
688 BAIL_ON_ERROR( dwError
);
690 pLabel
->pszLabel
= pszLabel
;
691 dwError
= DNSAppendLabel( pLabelList
, pLabel
, &pLabelList
);
692 BAIL_ON_ERROR( dwError
);
696 DNSAllocateMemory( sizeof( DNS_DOMAIN_NAME
),
697 ( void * ) &pDomainName
);
698 BAIL_ON_ERROR( dwError
);
699 pDomainName
->pLabelList
= pLabelList
;
701 *ppDomainName
= pDomainName
;
707 *ppDomainName
= NULL
;
711 /********************************************************************
712 ********************************************************************/
714 int32
DNSReceiveBufferMoveBackIndex( HANDLE hRecvBuffer
, int16 wOffset
)
717 DNS_RECEIVEBUFFER_CONTEXT
*pDNSContext
= NULL
;
719 pDNSContext
= ( DNS_RECEIVEBUFFER_CONTEXT
* ) hRecvBuffer
;
720 pDNSContext
->dwBytesRead
-= wOffset
;
725 /********************************************************************
726 ********************************************************************/
728 void DNSFreeSendBufferContext( HANDLE hSendBuffer
)
730 DNS_SENDBUFFER_CONTEXT
*pSendBufferContext
= NULL
;
732 pSendBufferContext
= ( DNS_SENDBUFFER_CONTEXT
* ) hSendBuffer
;
734 if ( pSendBufferContext
->pSendBuffer
) {
735 DNSFreeMemory( pSendBufferContext
->pSendBuffer
);
737 if ( pSendBufferContext
) {
738 DNSFreeMemory( pSendBufferContext
);
742 /********************************************************************
743 ********************************************************************/
745 int32
DNSGetSendBufferContextSize( HANDLE hSendBuffer
)
747 DNS_SENDBUFFER_CONTEXT
*pSendBufferContext
= NULL
;
749 pSendBufferContext
= ( DNS_SENDBUFFER_CONTEXT
* ) hSendBuffer
;
751 return ( pSendBufferContext
->dwBytesWritten
);
755 /********************************************************************
756 ********************************************************************/
758 uint8
*DNSGetSendBufferContextBuffer( HANDLE hSendBuffer
)
760 DNS_SENDBUFFER_CONTEXT
*pSendBufferContext
= NULL
;
762 pSendBufferContext
= ( DNS_SENDBUFFER_CONTEXT
* ) hSendBuffer
;
764 return ( pSendBufferContext
->pSendBuffer
);