@@ -13,6 +13,7 @@ const (
1313 errMsgGenToken = "GenerateVerificationToken() error = %v"
1414 errMsgGenTokenNormal = "GenerateVerificationToken() should succeed in normal conditions: %v"
1515 errMsgGenTokenWithInfo = "GenerateTokenWithInfo() error = %v"
16+ dnsRecordPrefix = "mcp-verify="
1617)
1718
1819func TestGenerateVerificationToken (t * testing.T ) {
@@ -228,7 +229,7 @@ func TestGenerateTokenWithInfo(t *testing.T) {
228229 t .Errorf ("TokenInfo.Encoding = %s, want base64url" , tokenInfo .Encoding )
229230 }
230231
231- expectedDNSRecord := "mcp-verify=" + tokenInfo .Token
232+ expectedDNSRecord := dnsRecordPrefix + tokenInfo .Token
232233 if tokenInfo .DNSRecord != expectedDNSRecord {
233234 t .Errorf ("TokenInfo.DNSRecord = %s, want %s" , tokenInfo .DNSRecord , expectedDNSRecord )
234235 }
@@ -283,14 +284,154 @@ func TestTokenDNSSafety(t *testing.T) {
283284 }
284285
285286 // Test full DNS record format
286- dnsRecord := "mcp-verify=" + token
287+ dnsRecord := dnsRecordPrefix + token
287288 MaxDNSRecordLength := 255
288289 if len (dnsRecord ) > MaxDNSRecordLength {
289290 t .Errorf ("DNS record too long (%d chars): %s" , len (dnsRecord ), dnsRecord )
290291 }
291292 }
292293}
293294
295+ func TestDNSTXTRecordRFCCompliance (t * testing.T ) {
296+ // Test DNS TXT record format compliance according to RFC 1035 and RFC 1464
297+ token , err := verification .GenerateVerificationToken ()
298+ if err != nil {
299+ t .Fatalf (errMsgGenToken , err )
300+ }
301+
302+ dnsRecord := dnsRecordPrefix + token
303+
304+ // RFC 1035: DNS names and TXT records have specific length limitations
305+ // TXT record data must not exceed 255 octets per string
306+ if len (dnsRecord ) > 255 {
307+ t .Errorf ("DNS TXT record exceeds 255 character limit: %d chars" , len (dnsRecord ))
308+ }
309+
310+ // RFC 1464: TXT records should follow attribute=value format
311+ if ! strings .Contains (dnsRecord , "=" ) {
312+ t .Error ("DNS TXT record missing required '=' separator" )
313+ }
314+
315+ parts := strings .SplitN (dnsRecord , "=" , 2 )
316+ if len (parts ) != 2 {
317+ t .Error ("DNS TXT record should have exactly one '=' separator" )
318+ }
319+
320+ attribute := parts [0 ]
321+ value := parts [1 ]
322+
323+ // Validate attribute name (should be "mcp-verify")
324+ expectedAttribute := strings .TrimSuffix (dnsRecordPrefix , "=" )
325+ if attribute != expectedAttribute {
326+ t .Errorf ("DNS TXT record attribute = %s, want %s" , attribute , expectedAttribute )
327+ }
328+
329+ // Validate that value is our token
330+ if value != token {
331+ t .Errorf ("DNS TXT record value = %s, want %s" , value , token )
332+ }
333+
334+ // Test that the record contains only ASCII printable characters (RFC compliant)
335+ for i , char := range dnsRecord {
336+ if char < 32 || char > 126 {
337+ t .Errorf ("DNS TXT record contains non-ASCII printable character at position %d: %c (code %d)" , i , char , char )
338+ }
339+ }
340+ }
341+
342+ func TestDNSTXTRecordTokenValidation (t * testing.T ) {
343+ // Test that tokens in DNS records are valid according to our format
344+ for i := 0 ; i < 50 ; i ++ {
345+ token , err := verification .GenerateVerificationToken ()
346+ if err != nil {
347+ t .Fatalf (errMsgGenTokenIteration , err , i )
348+ }
349+
350+ dnsRecord := dnsRecordPrefix + token
351+
352+ // Extract token from DNS record
353+ if ! strings .HasPrefix (dnsRecord , dnsRecordPrefix ) {
354+ t .Errorf ("DNS record missing expected prefix: %s" , dnsRecord )
355+ continue
356+ }
357+
358+ extractedToken := strings .TrimPrefix (dnsRecord , dnsRecordPrefix )
359+
360+ // Validate extracted token format
361+ if ! verification .ValidateTokenFormat (extractedToken ) {
362+ t .Errorf ("Extracted token from DNS record failed validation: %s" , extractedToken )
363+ }
364+
365+ // Ensure token matches what we generated
366+ if extractedToken != token {
367+ t .Errorf ("Extracted token %s does not match generated token %s" , extractedToken , token )
368+ }
369+ }
370+ }
371+
372+ func TestDNSTXTRecordSpecialCharacters (t * testing.T ) {
373+ // Test that DNS records handle RFC-compliant special characters correctly
374+ token , err := verification .GenerateVerificationToken ()
375+ if err != nil {
376+ t .Fatalf (errMsgGenToken , err )
377+ }
378+
379+ dnsRecord := dnsRecordPrefix + token
380+
381+ // Characters that should NOT appear in our DNS records
382+ prohibitedChars := []rune {
383+ 0 , // NULL
384+ 9 , // TAB
385+ 10 , // LF
386+ 13 , // CR
387+ 34 , // Double quote
388+ 92 , // Backslash
389+ 127 , // DEL
390+ }
391+
392+ for _ , prohibited := range prohibitedChars {
393+ if strings .ContainsRune (dnsRecord , prohibited ) {
394+ t .Errorf ("DNS record contains prohibited character: %c (code %d)" , prohibited , prohibited )
395+ }
396+ }
397+
398+ // Characters that SHOULD be allowed (base64url safe)
399+ allowedChars := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_="
400+ for _ , char := range dnsRecord {
401+ if ! strings .ContainsRune (allowedChars , char ) {
402+ t .Errorf ("DNS record contains unexpected character: %c (code %d)" , char , char )
403+ }
404+ }
405+ }
406+
407+ func TestDNSTXTRecordLength (t * testing.T ) {
408+ // Test DNS TXT record length constraints
409+ token , err := verification .GenerateVerificationToken ()
410+ if err != nil {
411+ t .Fatalf (errMsgGenToken , err )
412+ }
413+
414+ dnsRecord := dnsRecordPrefix + token
415+
416+ // RFC 1035: TXT record strings are limited to 255 octets
417+ maxTXTRecordLength := 255
418+ if len (dnsRecord ) > maxTXTRecordLength {
419+ t .Errorf ("DNS TXT record length %d exceeds RFC limit of %d" , len (dnsRecord ), maxTXTRecordLength )
420+ }
421+
422+ // Calculate expected length: "mcp-verify=" (11 chars) + token (22 chars) = 33 chars
423+ expectedLength := 11 + 22 // len("mcp-verify=") + token length
424+ if len (dnsRecord ) != expectedLength {
425+ t .Errorf ("DNS TXT record length %d, expected %d" , len (dnsRecord ), expectedLength )
426+ }
427+
428+ // Ensure we have reasonable margin below the limit
429+ marginRequired := 50 // Leave room for future changes
430+ if len (dnsRecord ) > (maxTXTRecordLength - marginRequired ) {
431+ t .Errorf ("DNS TXT record length %d too close to limit, needs %d char margin" , len (dnsRecord ), marginRequired )
432+ }
433+ }
434+
294435// Benchmark tests for performance
295436func BenchmarkGenerateVerificationToken (b * testing.B ) {
296437 for i := 0 ; i < b .N ; i ++ {
0 commit comments