2006-08-24 19:43:32 +04:00
/*
Linux DNS client library implementation
Copyright ( C ) 2006 Krishna Ganugapati < krishnag @ centeris . com >
Copyright ( C ) 2006 Gerald Carter < jerry @ samba . org >
* * NOTE ! The following LGPL license applies to the libaddns
* * library . This does NOT imply that all of Samba is released
* * under the LGPL
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
version 2.1 of the License , or ( at your option ) any later version .
This library is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
License along with this library ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA
02110 - 1301 USA
*/
# include "dns.h"
# include <ctype.h>
# define TRUE 1
# define FALSE 0
# define STATE_BEGIN 0
# define STATE_LABEL 1
# define STATE_FINISH 2
# define TOKEN_LABEL 1
# define TOKEN_SEPARATOR 2
# define TOKEN_EOS 3
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-09-04 01:07:16 +04:00
static int32 getToken ( const char * pszString , char * pszToken , int32 * pdwToken ,
2006-08-24 19:43:32 +04:00
int32 * pdwPosition )
{
int32 dwError = 0 ;
char c = 0 ;
int32 dwToken = 0 ;
int32 i = 0 ;
int32 dwState = 0 ;
int32 dwPosition = 0 ;
dwPosition = * pdwPosition ;
dwState = STATE_BEGIN ;
while ( dwState ! = STATE_FINISH ) {
c = pszString [ dwPosition ] ;
if ( c = = ' \0 ' ) {
if ( dwState = = STATE_LABEL ) {
dwToken = TOKEN_LABEL ;
dwState = STATE_FINISH ;
continue ;
} else if ( dwState = = STATE_BEGIN ) {
dwToken = TOKEN_EOS ;
dwState = STATE_FINISH ;
continue ;
}
} else if ( isalnum ( c ) | | c = = ' - ' ) {
pszToken [ i + + ] = c ;
dwPosition + + ;
dwState = STATE_LABEL ;
continue ;
} else if ( c = = ' . ' ) {
if ( dwState = = STATE_LABEL ) {
dwToken = TOKEN_LABEL ;
dwState = STATE_FINISH ;
continue ;
} else if ( dwState = = STATE_BEGIN ) {
dwToken = TOKEN_SEPARATOR ;
dwPosition + + ;
dwState = STATE_FINISH ;
continue ;
}
} else {
if ( dwState = = STATE_LABEL ) {
dwToken = TOKEN_LABEL ;
dwState = STATE_FINISH ;
} else if ( dwState = = 0 ) {
dwError = ERROR_INVALID_PARAMETER ;
dwState = STATE_FINISH ;
}
}
}
* pdwPosition = dwPosition ;
* pdwToken = dwToken ;
return dwError ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int32 DNSMakeLabel ( char * szLabel , DNS_DOMAIN_LABEL * * ppLabel )
{
DNS_DOMAIN_LABEL * pLabel = NULL ;
char * pszLabel = NULL ;
int32 dwError = 0 ;
dwError =
DNSAllocateMemory ( sizeof ( DNS_DOMAIN_LABEL ) ,
2006-08-25 00:17:59 +04:00
( void * ) & pLabel ) ;
2006-08-24 19:43:32 +04:00
BAIL_ON_ERROR ( dwError ) ;
dwError = DNSAllocateString ( szLabel , & pszLabel ) ;
BAIL_ON_ERROR ( dwError ) ;
pLabel - > pszLabel = pszLabel ;
pLabel - > dwLength = ( int32 ) strlen ( pszLabel ) ;
* ppLabel = pLabel ;
return dwError ;
error :
if ( pLabel ) {
DNSFreeMemory ( pLabel ) ;
}
* ppLabel = NULL ;
return dwError ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void DNSFreeLabel ( DNS_DOMAIN_LABEL * pLabel )
{
if ( pLabel ) {
DNSFreeMemory ( pLabel ) ;
}
return ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DNSFreeLabelList ( DNS_DOMAIN_LABEL * pLabelList )
{
DNS_DOMAIN_LABEL * pTemp = NULL ;
while ( pLabelList ) {
pTemp = pLabelList ;
pLabelList = pLabelList - > pNext ;
DNSFreeLabel ( pTemp ) ;
}
return ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DNSFreeDomainName ( DNS_DOMAIN_NAME * pDomainName )
{
DNSFreeLabelList ( pDomainName - > pLabelList ) ;
DNSFreeMemory ( pDomainName ) ;
return ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-09-04 01:07:16 +04:00
static int32 LabelList ( const char * pszString , int32 * pdwPosition , DNS_DOMAIN_LABEL * * ppList )
2006-08-24 19:43:32 +04:00
{
int32 dwError = 0 ;
DNS_DOMAIN_LABEL * pList = NULL ;
DNS_DOMAIN_LABEL * pLabel = NULL ;
int32 dwToken = 0 ;
char szToken [ 64 ] ;
memset ( szToken , 0 , 64 ) ;
dwError = getToken ( pszString , szToken , & dwToken , pdwPosition ) ;
BAIL_ON_ERROR ( dwError ) ;
if ( dwToken ! = TOKEN_LABEL ) {
dwError = ERROR_INVALID_PARAMETER ;
BAIL_ON_ERROR ( dwError ) ;
}
dwError = DNSMakeLabel ( szToken , & pLabel ) ;
BAIL_ON_ERROR ( dwError ) ;
memset ( szToken , 0 , 64 ) ;
dwError = getToken ( pszString , szToken , & dwToken , pdwPosition ) ;
BAIL_ON_ERROR ( dwError ) ;
if ( dwToken = = TOKEN_EOS ) {
* ppList = pLabel ;
return dwError ;
} else if ( dwToken = = TOKEN_SEPARATOR ) {
dwError = LabelList ( pszString , pdwPosition , & pList ) ;
BAIL_ON_ERROR ( dwError ) ;
pLabel - > pNext = pList ;
* ppList = pLabel ;
}
return dwError ;
error :
if ( pLabel ) {
DNSFreeLabel ( pLabel ) ;
}
return dwError ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int32 DNSGetDomainNameOffset ( uint8 * pBuffer )
{
uint8 uLen = 0 ;
uint8 uLen1 ;
int32 dwOffset = 0 ;
uLen1 = * pBuffer ;
if ( uLen1 & 0xC0 ) {
dwOffset + = 2 ;
} else {
while ( 1 ) {
uLen = * pBuffer ;
pBuffer + + ;
dwOffset + + ;
if ( uLen = = 0 ) {
break ;
}
dwOffset + = uLen ;
pBuffer + = uLen ;
}
}
return ( dwOffset ) ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int32 DNSGenerateIdentifier ( int16 * pwIdentifier )
{
int32 dwError = 0 ;
* pwIdentifier = random ( ) ;
return dwError ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int32 DNSGetDomainNameLength ( DNS_DOMAIN_NAME * pDomainName , int32 * pdwLength )
{
int32 dwError = 0 ;
int32 dwLength = 0 ;
DNS_DOMAIN_LABEL * pDomainLabel = NULL ;
if ( ! pDomainName ) {
dwError = ERROR_INVALID_PARAMETER ;
BAIL_ON_ERROR ( dwError ) ;
}
pDomainLabel = pDomainName - > pLabelList ;
while ( pDomainLabel ) {
dwLength + = pDomainLabel - > dwLength ;
dwLength + = 1 ;
pDomainLabel = pDomainLabel - > pNext ;
}
dwLength + = 1 ;
* pdwLength = dwLength ;
return dwError ;
error :
* pdwLength = 0 ;
return dwError ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int32 DNSCopyDomainName ( uint8 * pBuffer ,
DNS_DOMAIN_NAME * pDomainName , int32 * pdwCopied )
{
int32 dwError = 0 ;
DNS_DOMAIN_LABEL * pDomainLabel = NULL ;
uint8 uChar = 0 ;
int32 dwCopied = 0 ;
if ( ! pDomainName ) {
dwError = ERROR_INVALID_PARAMETER ;
BAIL_ON_ERROR ( dwError ) ;
}
pDomainLabel = pDomainName - > pLabelList ;
while ( pDomainLabel ) {
uChar = ( uint8 ) pDomainLabel - > dwLength ;
memcpy ( pBuffer + dwCopied , & uChar , sizeof ( uint8 ) ) ;
dwCopied + = sizeof ( uint8 ) ;
memcpy ( pBuffer + dwCopied , pDomainLabel - > pszLabel ,
pDomainLabel - > dwLength ) ;
dwCopied + = pDomainLabel - > dwLength ;
pDomainLabel = pDomainLabel - > pNext ;
}
uChar = 0 ;
memcpy ( pBuffer + dwCopied , & uChar , sizeof ( uint8 ) ) ;
dwCopied + = sizeof ( uint8 ) ;
* pdwCopied = dwCopied ;
return dwError ;
error :
* pdwCopied = 0 ;
return dwError ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int32 DNSGenerateKeyName ( char * * ppszKeyName )
{
int32 dwError = 0 ;
2006-08-24 20:33:50 +04:00
# if defined(WITH_DNS_UPDATES)
2006-08-24 19:43:32 +04:00
char * pszKeyName = NULL ;
char szTemp [ 256 ] ;
char szBuffer [ 256 ] ;
unsigned char uuid [ 16 ] ;
memset ( szTemp , 0 , 256 ) ;
memset ( szBuffer , 0 , 256 ) ;
memset ( uuid , 0 , 16 ) ;
uuid_generate ( uuid ) ;
uuid_unparse ( uuid , szBuffer ) ;
strcpy ( szTemp , szBuffer ) ;
dwError = DNSAllocateString ( szTemp , & pszKeyName ) ;
BAIL_ON_ERROR ( dwError ) ;
* ppszKeyName = pszKeyName ;
return dwError ;
error :
2006-08-24 20:33:50 +04:00
# endif
2006-08-24 19:43:32 +04:00
* ppszKeyName = NULL ;
return dwError ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-09-04 01:07:16 +04:00
int32 DNSDomainNameFromString ( const char * pszDomainName ,
2006-08-24 19:43:32 +04:00
DNS_DOMAIN_NAME * * ppDomainName )
{
int32 dwError = 0 ;
int32 dwPosition = 0 ;
DNS_DOMAIN_NAME * pDomainName = NULL ;
DNS_DOMAIN_LABEL * pLabelList = NULL ;
if ( ! pszDomainName | | ! * pszDomainName ) {
dwError = ERROR_INVALID_PARAMETER ;
return dwError ;
}
dwError = LabelList ( pszDomainName , & dwPosition , & pLabelList ) ;
BAIL_ON_ERROR ( dwError ) ;
dwError =
DNSAllocateMemory ( sizeof ( DNS_DOMAIN_NAME ) ,
2006-08-25 00:17:59 +04:00
( void * ) & pDomainName ) ;
2006-08-24 19:43:32 +04:00
BAIL_ON_ERROR ( dwError ) ;
pDomainName - > pLabelList = pLabelList ;
* ppDomainName = pDomainName ;
return dwError ;
error :
if ( pLabelList ) {
DNSFreeLabelList ( pLabelList ) ;
}
* ppDomainName = NULL ;
return dwError ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int32 DNSAppendLabel ( DNS_DOMAIN_LABEL * pLabelList ,
DNS_DOMAIN_LABEL * pLabel ,
DNS_DOMAIN_LABEL * * ppNewLabelList )
{
DNS_DOMAIN_LABEL * * ppLabelList = NULL ;
int32 dwError = 0 ;
if ( pLabelList = = NULL ) {
* ppNewLabelList = pLabel ;
return dwError ;
}
ppLabelList = & pLabelList ;
while ( ( * ppLabelList ) - > pNext ) {
ppLabelList = & ( ( * ppLabelList ) - > pNext ) ;
}
( * ppLabelList ) - > pNext = pLabel ;
* ppNewLabelList = pLabelList ;
return dwError ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int32 GetLastError ( )
{
return ( errno ) ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int32 WSAGetLastError ( void )
{
return ( errno ) ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DNSRecordGenerateOffsets ( DNS_RR_RECORD * pDNSRecord )
{
int32 dwOffset = 0 ;
uint8 * pRData = NULL ;
int16 wKeySize , wnKeySize = 0 ;
pRData = pDNSRecord - > pRData ;
switch ( pDNSRecord - > RRHeader . wType ) {
case QTYPE_TKEY :
pDNSRecord - > Offsets . TKey . wAlgorithmOffset =
( int16 ) dwOffset ;
dwOffset + = DNSGetDomainNameOffset ( pRData ) ;
pDNSRecord - > Offsets . TKey . wInceptionOffset =
( int16 ) dwOffset ;
dwOffset + = sizeof ( int32 ) ;
pDNSRecord - > Offsets . TKey . wExpirationOffset =
( int16 ) dwOffset ;
dwOffset + = sizeof ( int32 ) ;
pDNSRecord - > Offsets . TKey . wModeOffset = ( int16 ) dwOffset ;
dwOffset + = sizeof ( int16 ) ;
pDNSRecord - > Offsets . TKey . wErrorOffset = ( int16 ) dwOffset ;
dwOffset + = sizeof ( int16 ) ;
pDNSRecord - > Offsets . TKey . wKeySizeOffset = ( int16 ) dwOffset ;
dwOffset + = sizeof ( int16 ) ;
pDNSRecord - > Offsets . TKey . wKeyDataOffset = ( int16 ) dwOffset ;
memcpy ( & wnKeySize ,
pRData + pDNSRecord - > Offsets . TKey . wKeySizeOffset ,
sizeof ( int16 ) ) ;
wKeySize = ntohs ( wnKeySize ) ;
dwOffset + = wKeySize ;
pDNSRecord - > Offsets . TKey . wOtherSizeOffset =
( int16 ) dwOffset ;
dwOffset + = sizeof ( int16 ) ;
pDNSRecord - > Offsets . TKey . wOtherDataOffset =
( int16 ) dwOffset ;
break ;
case QTYPE_TSIG :
break ;
}
return ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int32 MapDNSResponseCodes ( int16 wResponseCode )
{
int16 wnResponseCode = 0 ;
uint8 * pByte = NULL ;
wnResponseCode = htons ( wResponseCode ) ;
pByte = ( uint8 * ) & wnResponseCode ;
#if 0
printf ( " Byte 0 - %.2x \n " , pByte [ 0 ] ) ;
printf ( " Byte 1 - %.2x \n " , pByte [ 1 ] ) ;
# endif
/* Bit 3, 2, 1, 0 of Byte 2 represent the RCode */
return ( ( int32 ) pByte [ 1 ] ) ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-08-25 00:17:59 +04:00
int32 DNSAllocateMemory ( int32 dwSize , void * _ppMemory )
2006-08-24 19:43:32 +04:00
{
2006-08-25 00:17:59 +04:00
void * * ppMemory = ( void * * ) _ppMemory ;
2006-08-24 19:43:32 +04:00
int32 dwError = 0 ;
void * pMemory = NULL ;
pMemory = malloc ( dwSize ) ;
if ( ! pMemory ) {
dwError = ERROR_OUTOFMEMORY ;
* ppMemory = NULL ;
} else {
memset ( pMemory , 0 , dwSize ) ;
* ppMemory = pMemory ;
}
return ( dwError ) ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-08-25 00:17:59 +04:00
int32 DNSReallocMemory ( void * pMemory , void * _ppNewMemory , int32 dwSize )
2006-08-24 19:43:32 +04:00
{
2006-08-25 00:17:59 +04:00
void * * ppNewMemory = ( void * * ) _ppNewMemory ;
2006-08-24 19:43:32 +04:00
int32 dwError = 0 ;
void * pNewMemory = NULL ;
if ( pMemory = = NULL ) {
pNewMemory = malloc ( dwSize ) ;
memset ( pNewMemory , 0 , dwSize ) ;
} else {
pNewMemory = realloc ( pMemory , dwSize ) ;
}
if ( ! pNewMemory ) {
dwError = ERROR_OUTOFMEMORY ;
* ppNewMemory = NULL ;
} else {
* ppNewMemory = pNewMemory ;
}
return ( dwError ) ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DNSFreeMemory ( void * pMemory )
{
free ( pMemory ) ;
return ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int32 DNSAllocateString ( char * pszInputString , char * * ppszOutputString )
{
int32 dwError = 0 ;
int32 dwLen = 0 ;
char * pszOutputString = NULL ;
if ( ! pszInputString | | ! * pszInputString ) {
dwError = ERROR_INVALID_PARAMETER ;
BAIL_ON_ERROR ( dwError ) ;
}
dwLen = ( int32 ) strlen ( pszInputString ) ;
2006-08-25 00:17:59 +04:00
dwError = DNSAllocateMemory ( dwLen + 1 , ( void * ) & pszOutputString ) ;
2006-08-24 19:43:32 +04:00
BAIL_ON_ERROR ( dwError ) ;
strcpy ( pszOutputString , pszInputString ) ;
* ppszOutputString = pszOutputString ;
return ( dwError ) ;
error :
* ppszOutputString = pszOutputString ;
return ( dwError ) ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DNSFreeString ( char * pszString )
{
return ;
}