2 Copyright (c) 2016-2019 Apple Inc. All rights reserved.
5 #include "DNSMessage.h"
7 //===========================================================================================================================
9 #define IsCompressionByte( X ) ( ( ( X ) & 0xC0 ) == 0xC0 )
12 DNSMessageExtractDomainName(
13 const uint8_t * inMsgPtr
,
15 const uint8_t * inPtr
,
16 uint8_t outName
[ kDomainNameLengthMax
],
17 const uint8_t ** outPtr
)
20 const uint8_t * label
;
22 const uint8_t * nextLabel
;
23 const uint8_t * const msgEnd
= inMsgPtr
+ inMsgLen
;
24 uint8_t * dst
= outName
;
25 const uint8_t * const dstLim
= outName
? ( outName
+ kDomainNameLengthMax
) : NULL
;
26 const uint8_t * nameEnd
= NULL
;
28 require_action_quiet( ( inPtr
>= inMsgPtr
) && ( inPtr
< msgEnd
), exit
, err
= kRangeErr
);
30 for( label
= inPtr
; ( labelLen
= label
[ 0 ] ) != 0; label
= nextLabel
)
32 if( labelLen
<= kDomainLabelLengthMax
)
34 nextLabel
= label
+ 1 + labelLen
;
35 require_action_quiet( nextLabel
< msgEnd
, exit
, err
= kUnderrunErr
);
38 require_action_quiet( ( dstLim
- dst
) > ( 1 + labelLen
), exit
, err
= kOverrunErr
);
39 memcpy( dst
, label
, 1 + labelLen
);
40 dst
+= ( 1 + labelLen
);
43 else if( IsCompressionByte( labelLen
) )
47 require_action_quiet( ( msgEnd
- label
) >= 2, exit
, err
= kUnderrunErr
);
53 offset
= (uint16_t)( ( ( label
[ 0 ] & 0x3F ) << 8 ) | label
[ 1 ] );
54 nextLabel
= inMsgPtr
+ offset
;
55 require_action_quiet( nextLabel
< msgEnd
, exit
, err
= kUnderrunErr
);
56 require_action_quiet( !IsCompressionByte( nextLabel
[ 0 ] ), exit
, err
= kMalformedErr
);
66 if( !nameEnd
) nameEnd
= label
+ 1;
68 if( outPtr
) *outPtr
= nameEnd
;
75 //===========================================================================================================================
78 DNSMessageExtractDomainNameString(
79 const void * inMsgPtr
,
82 char inBuf
[ kDNSServiceMaxDomainName
],
83 const uint8_t ** outPtr
)
86 const uint8_t * nextPtr
;
87 uint8_t domainName
[ kDomainNameLengthMax
];
89 err
= DNSMessageExtractDomainName( inMsgPtr
, inMsgLen
, inPtr
, domainName
, &nextPtr
);
90 require_noerr_quiet( err
, exit
);
92 err
= DomainNameToString( domainName
, NULL
, inBuf
, NULL
);
93 require_noerr_quiet( err
, exit
);
95 if( outPtr
) *outPtr
= nextPtr
;
101 //===========================================================================================================================
104 DNSMessageExtractQuestion(
105 const uint8_t * inMsgPtr
,
107 const uint8_t * inPtr
,
108 uint8_t outName
[ kDomainNameLengthMax
],
111 const uint8_t ** outPtr
)
114 const uint8_t * const msgEnd
= &inMsgPtr
[ inMsgLen
];
116 const dns_fixed_fields_question
* fields
;
118 err
= DNSMessageExtractDomainName( inMsgPtr
, inMsgLen
, inPtr
, outName
, &ptr
);
119 require_noerr_quiet( err
, exit
);
120 require_action_quiet( (size_t)( msgEnd
- ptr
) >= sizeof( dns_fixed_fields_question
), exit
, err
= kUnderrunErr
);
122 fields
= (const dns_fixed_fields_question
*) ptr
;
123 if( outType
) *outType
= dns_fixed_fields_question_get_type( fields
);
124 if( outClass
) *outClass
= dns_fixed_fields_question_get_class( fields
);
125 if( outPtr
) *outPtr
= (const uint8_t *) &fields
[ 1 ];
131 //===========================================================================================================================
134 DNSMessageExtractRecord(
135 const uint8_t * inMsgPtr
,
137 const uint8_t * inPtr
,
138 uint8_t outName
[ kDomainNameLengthMax
],
142 const uint8_t ** outRDataPtr
,
143 size_t * outRDataLen
,
144 const uint8_t ** outPtr
)
147 const uint8_t * const msgEnd
= inMsgPtr
+ inMsgLen
;
149 const dns_fixed_fields_record
* fields
;
150 const uint8_t * rdata
;
153 err
= DNSMessageExtractDomainName( inMsgPtr
, inMsgLen
, inPtr
, outName
, &ptr
);
154 require_noerr_quiet( err
, exit
);
155 require_action_quiet( (size_t)( msgEnd
- ptr
) >= sizeof( *fields
), exit
, err
= kUnderrunErr
);
157 fields
= (const dns_fixed_fields_record
*) ptr
;
158 rdata
= ptr
+ sizeof( *fields
);
160 rdLength
= dns_fixed_fields_record_get_rdlength( fields
);
161 require_action_quiet( (size_t)( msgEnd
- rdata
) >= rdLength
, exit
, err
= kUnderrunErr
);
163 if( outType
) *outType
= dns_fixed_fields_record_get_type( fields
);
164 if( outClass
) *outClass
= dns_fixed_fields_record_get_class( fields
);
165 if( outTTL
) *outTTL
= dns_fixed_fields_record_get_ttl( fields
);
166 if( outRDataPtr
) *outRDataPtr
= rdata
;
167 if( outRDataLen
) *outRDataLen
= rdLength
;
168 if( outPtr
) *outPtr
= &rdata
[ rdLength
];
174 //===========================================================================================================================
176 OSStatus
DNSMessageGetAnswerSection( const uint8_t *inMsgPtr
, size_t inMsgLen
, const uint8_t **outPtr
)
179 unsigned int questionCount
, i
;
180 const DNSHeader
* hdr
;
183 require_action_quiet( inMsgLen
>= kDNSHeaderLength
, exit
, err
= kSizeErr
);
185 hdr
= (DNSHeader
*) inMsgPtr
;
186 questionCount
= DNSHeaderGetQuestionCount( hdr
);
188 ptr
= (const uint8_t *) &hdr
[ 1 ];
189 for( i
= 0; i
< questionCount
; ++i
)
191 err
= DNSMessageExtractQuestion( inMsgPtr
, inMsgLen
, ptr
, NULL
, NULL
, NULL
, &ptr
);
192 require_noerr_quiet( err
, exit
);
195 if( outPtr
) *outPtr
= ptr
;
202 //===========================================================================================================================
205 DNSMessageWriteQuery(
208 const uint8_t * inQName
,
211 uint8_t outMsg
[ STATIC_PARAM kDNSQueryMessageMaxLen
],
215 DNSHeader
* const hdr
= (DNSHeader
*) outMsg
;
220 memset( hdr
, 0, sizeof( *hdr
) );
221 DNSHeaderSetID( hdr
, inMsgID
);
222 DNSHeaderSetFlags( hdr
, inFlags
);
223 DNSHeaderSetQuestionCount( hdr
, 1 );
225 qnameLen
= DomainNameLength( inQName
);
226 require_action_quiet( qnameLen
<= kDomainNameLengthMax
, exit
, err
= kSizeErr
);
228 ptr
= (uint8_t *) &hdr
[ 1 ];
229 memcpy( ptr
, inQName
, qnameLen
);
232 dns_fixed_fields_question_init( (dns_fixed_fields_question
*) ptr
, inQType
, inQClass
);
233 ptr
+= sizeof( dns_fixed_fields_question
);
235 msgLen
= (size_t)( ptr
- outMsg
);
237 if( outLen
) *outLen
= msgLen
;
244 //===========================================================================================================================
247 DomainNameAppendString(
248 uint8_t inDomainName
[ STATIC_PARAM kDomainNameLengthMax
],
249 const char * inString
,
255 const uint8_t * const nameLim
= inDomainName
+ kDomainNameLengthMax
;
257 for( root
= inDomainName
; ( root
< nameLim
) && *root
; root
+= ( 1 + *root
) ) {}
258 require_action_quiet( root
< nameLim
, exit
, err
= kMalformedErr
);
260 // If the string is a single dot, denoting the root domain, then there are no non-empty labels.
263 if( ( src
[ 0 ] == '.' ) && ( src
[ 1 ] == '\0' ) ) ++src
;
266 uint8_t * const label
= root
;
267 const uint8_t * const labelLim
= Min( &label
[ 1 + kDomainLabelLengthMax
], nameLim
- 1 );
273 while( *src
&& ( ( c
= *src
++ ) != '.' ) )
277 require_action_quiet( *src
!= '\0', exit
, err
= kUnderrunErr
);
279 if( isdigit_safe( c
) && isdigit_safe( src
[ 0 ] ) && isdigit_safe( src
[ 1 ] ) )
281 const int decimal
= ( ( c
- '0' ) * 100 ) + ( ( src
[ 0 ] - '0' ) * 10 ) + ( src
[ 1 ] - '0' );
290 require_action_quiet( dst
< labelLim
, exit
, err
= kOverrunErr
);
291 *dst
++ = (uint8_t) c
;
294 labelLen
= (size_t)( dst
- &label
[ 1 ] );
295 require_action_quiet( labelLen
> 0, exit
, err
= kMalformedErr
);
297 label
[ 0 ] = (uint8_t) labelLen
;
302 if( outEnd
) *outEnd
= root
+ 1;
309 //===========================================================================================================================
311 OSStatus
DomainNameDupEx( const uint8_t *inName
, Boolean inLower
, uint8_t **outNamePtr
, size_t *outNameLen
)
315 const size_t nameLen
= DomainNameLength( inName
);
317 namePtr
= (uint8_t *) malloc( nameLen
);
318 require_action_quiet( namePtr
, exit
, err
= kNoMemoryErr
);
328 while( ( len
= *src
) != 0 )
333 const int c
= *src
++;
334 *dst
++ = (uint8_t) tolower_safe( c
);
341 memcpy( namePtr
, inName
, nameLen
);
344 *outNamePtr
= namePtr
;
345 if( outNameLen
) *outNameLen
= nameLen
;
352 //===========================================================================================================================
354 Boolean
DomainNameEqual( const uint8_t *inName1
, const uint8_t *inName2
)
356 const uint8_t * p1
= inName1
;
357 const uint8_t * p2
= inName2
;
358 if( p1
== p2
) return( true );
362 const int len2
= *p2
++;
363 if( len1
!= len2
) return( false );
364 if( len1
== 0 ) return( true );
367 const int c1
= *p1
++;
368 const int c2
= *p2
++;
369 if( tolower_safe( c1
) != tolower_safe( c2
) ) return( false );
374 //===========================================================================================================================
377 DomainNameFromString(
378 uint8_t outName
[ STATIC_PARAM kDomainNameLengthMax
],
379 const char * inString
,
383 return( DomainNameAppendString( outName
, inString
, outEnd
) );
386 //===========================================================================================================================
390 const uint8_t * inName
,
391 const uint8_t * inLimit
,
392 char outString
[ STATIC_PARAM kDNSServiceMaxDomainName
],
393 const uint8_t ** outPtr
)
396 const uint8_t * label
;
398 const uint8_t * nextLabel
;
402 require_action_quiet( !inLimit
|| ( inName
< inLimit
), exit
, err
= kUnderrunErr
);
404 // Convert each label up until the root label, i.e., the zero-length label.
407 for( label
= inName
; ( labelLen
= label
[ 0 ] ) != 0; label
= nextLabel
)
409 require_action_quiet( labelLen
<= kDomainLabelLengthMax
, exit
, err
= kMalformedErr
);
411 nextLabel
= &label
[ 1 + labelLen
];
412 require_action_quiet( ( nextLabel
- inName
) < kDomainNameLengthMax
, exit
, err
= kMalformedErr
);
413 require_action_quiet( !inLimit
|| ( nextLabel
< inLimit
), exit
, err
= kUnderrunErr
);
415 for( src
= &label
[ 1 ]; src
< nextLabel
; ++src
)
417 // Only allow 7-bit ASCII characters.
418 if( ( *src
>= 32 ) && ( *src
<= 126 ) )
420 if( ( *src
== '.' ) || ( *src
== '\\' ) || ( *src
== ' ' ) ) *dst
++ = '\\';
421 *dst
++ = (char) *src
;
426 *dst
++ = '0' + ( *src
/ 100 );
427 *dst
++ = '0' + ( ( *src
/ 10 ) % 10 );
428 *dst
++ = '0' + ( *src
% 10 );
434 // At this point, label points to the root label.
435 // If the root label was the only label, then write a dot for it.
437 if( label
== inName
) *dst
++ = '.';
439 if( outPtr
) *outPtr
= label
+ 1;