@@ -317,7 +317,8 @@ test('Packet#encode', function () {
317317 type : Packet . TYPE . TXT ,
318318 class : Packet . CLASS . IN ,
319319 ttl : 300 ,
320- data : '#v=spf1 include:_spf.google.com ~all' ,
320+ // TXT data is an array of <character-string> items (RFC 1035 §3.3.14).
321+ data : [ '#v=spf1 include:_spf.google.com ~all' ] ,
321322 } ) ;
322323
323324 assert . deepEqual ( Packet . parse ( response . toBuffer ( ) ) , response ) ;
@@ -343,10 +344,7 @@ test('Packet#encode array of character strings', function () {
343344 data : dkim ,
344345 } ) ;
345346
346- assert . equal (
347- Packet . parse ( response . toBuffer ( ) ) . answers [ 0 ] . data ,
348- dkim . join ( '' ) ,
349- ) ;
347+ assert . deepEqual ( Packet . parse ( response . toBuffer ( ) ) . answers [ 0 ] . data , dkim ) ;
350348} ) ;
351349
352350test ( 'EDNS.ECS#encode' , function ( ) {
@@ -511,9 +509,9 @@ test('Resource#TXT round-trip single string', function () {
511509 type : Packet . TYPE . TXT ,
512510 class : Packet . CLASS . IN ,
513511 ttl : 300 ,
514- data : 'hello world' ,
512+ data : 'hello world' , // encoder normalizes string → [string]
515513 } ) ;
516- assert . equal ( out . data , 'hello world' ) ;
514+ assert . deepEqual ( out . data , [ 'hello world' ] ) ;
517515} ) ;
518516
519517test ( 'Resource#TXT round-trip with utf-8' , function ( ) {
@@ -524,7 +522,57 @@ test('Resource#TXT round-trip with utf-8', function () {
524522 ttl : 300 ,
525523 data : 'café résumé 日本' ,
526524 } ) ;
527- assert . equal ( out . data , 'café résumé 日本' ) ;
525+ assert . deepEqual ( out . data , [ 'café résumé 日本' ] ) ;
526+ } ) ;
527+
528+ test ( 'Resource#TXT preserves character-string boundaries' , function ( ) {
529+ // SPF/DKIM-style multi-string TXT records must not be merged on decode.
530+ const chunks = [ 'part-one ' , 'part-two ' , 'part-three' ] ;
531+ const out = roundTripAnswer ( {
532+ name : 'multi.example' ,
533+ type : Packet . TYPE . TXT ,
534+ class : Packet . CLASS . IN ,
535+ ttl : 60 ,
536+ data : chunks ,
537+ } ) ;
538+ assert . deepEqual ( out . data , chunks ) ;
539+ } ) ;
540+
541+ test ( 'Resource#TXT decode rejects character-string overruns RDATA' , function ( ) {
542+ // Hand-built TXT rdata: rdlength=5, but the first character-string claims
543+ // length 10. Direct caller should see a thrown error.
544+ const reader = new Packet . Reader ( Buffer . from ( [ 0x0a , 0x61 , 0x62 , 0x63 , 0x64 ] ) ) ;
545+ assert . throws (
546+ ( ) => Packet . Resource . TXT . decode . call ( { } , reader , 5 ) ,
547+ / o v e r r u n s R D A T A / ,
548+ ) ;
549+ } ) ;
550+
551+ test ( 'Resource#TXT decode error does not cascade to following RRs' , function ( ) {
552+ // A malformed TXT record (rdlength=5, chunkLength=10) must consume its
553+ // declared rdlength before throwing, so the A record after it parses
554+ // cleanly. Without the bounds check the reader would be misaligned and
555+ // the second record would be lost.
556+ const pkt = Buffer . from ( [
557+ // header: id=1, ancount=2, others 0
558+ 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x02 , 0x00 , 0x00 , 0x00 , 0x00 ,
559+ // answer 1: name "t", TYPE=TXT, CLASS=IN, TTL=60, RDLENGTH=5,
560+ // rdata = [chunkLen=10, 4 bogus bytes] ← chunkLen overruns
561+ 0x01 , 0x74 , 0x00 , 0x00 , 0x10 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x3c , 0x00 ,
562+ 0x05 , 0x0a , 0x61 , 0x62 , 0x63 , 0x64 ,
563+ // answer 2: name "a", TYPE=A, CLASS=IN, TTL=60, RDLENGTH=4, 192.0.2.7
564+ 0x01 , 0x61 , 0x00 , 0x00 , 0x01 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x3c , 0x00 ,
565+ 0x04 , 0xc0 , 0x00 , 0x02 , 0x07 ,
566+ ] ) ;
567+ const parsed = Packet . parse ( pkt ) ;
568+ assert . equal (
569+ parsed . answers . length ,
570+ 1 ,
571+ 'the malformed TXT should be dropped, leaving only the A record' ,
572+ ) ;
573+ assert . equal ( parsed . answers [ 0 ] . type , Packet . TYPE . A ) ;
574+ assert . equal ( parsed . answers [ 0 ] . name , 'a' ) ;
575+ assert . equal ( parsed . answers [ 0 ] . address , '192.0.2.7' ) ;
528576} ) ;
529577
530578test ( 'Resource#SOA round-trip' , function ( ) {
0 commit comments