@@ -88,4 +88,119 @@ void canParseZoneWithSigs() throws IOException {
8888 assertThat (onlyKeySet .rrs ()).hasSize (1 );
8989 assertThat (onlyKeySet .sigs ()).hasSize (0 );
9090 }
91+
92+ @ Test
93+ void canReplaceSoa () throws IOException {
94+ Name an = Name .fromString ("10.in-addr.arpa." );
95+ Name host = Name .fromString ("z.example.com." );
96+ Name secondary = Name .fromString ("y.example.com." );
97+ Name admin = Name .fromString ("dns-ops.example.com." );
98+ Name admin2 = Name .fromString ("dns-ops2.example.com." );
99+
100+ long ttl = 86400 ;
101+ long serial = 2147483749L ;
102+ long refresh = 1800 ;
103+ long retry = 900 ;
104+ long expire = 691200 ;
105+ long minimum = 10800 ;
106+
107+ Record soa =
108+ new SOARecord (an , DClass .IN , ttl , host , admin , serial , refresh , retry , expire , minimum );
109+ Record soaRrsig =
110+ new RRSIGRecord (
111+ an ,
112+ DClass .IN ,
113+ ttl ,
114+ Type .SOA ,
115+ 5 ,
116+ ttl ,
117+ Instant .now (),
118+ Instant .now (),
119+ 5 ,
120+ an ,
121+ "soa1Sig" .getBytes (StandardCharsets .UTF_8 ));
122+
123+ // for otherSoa, admin is different than the original
124+ Record otherSoa =
125+ new SOARecord (an , DClass .IN , ttl , host , admin2 , serial , refresh , retry , expire , minimum );
126+ // for oatherSoaRrsig sig is different from the original
127+ Record oatherSoaRrsig =
128+ new RRSIGRecord (
129+ an ,
130+ DClass .IN ,
131+ ttl ,
132+ Type .SOA ,
133+ 5 ,
134+ ttl ,
135+ Instant .now (),
136+ Instant .now (),
137+ 5 ,
138+ an ,
139+ "soa2sig" .getBytes (StandardCharsets .UTF_8 ));
140+
141+ Record nsSig =
142+ new RRSIGRecord (
143+ an ,
144+ DClass .IN ,
145+ ttl ,
146+ Type .NS ,
147+ 5 ,
148+ ttl ,
149+ Instant .now (),
150+ Instant .now (),
151+ 5 ,
152+ an ,
153+ "nsSig" .getBytes (StandardCharsets .UTF_8 ));
154+
155+ // dummy set of records for a dummy zone
156+ Record [] records =
157+ new Record [] {
158+ soa ,
159+ new NSRecord (an , DClass .IN , ttl , host ),
160+ new NSRecord (an , DClass .IN , ttl , secondary ),
161+ new DNSKEYRecord (
162+ an , DClass .IN , ttl , 256 , 3 , 5 , "dummypublickey" .getBytes (StandardCharsets .UTF_8 )),
163+ nsSig ,
164+ soaRrsig
165+ };
166+
167+ Zone z = new Zone (an , records );
168+ // replace Soa
169+ z .addRecord (otherSoa );
170+ // replace RRSig covering Soa
171+ z .removeRecord (soaRrsig );
172+ z .addRecord (oatherSoaRrsig );
173+
174+ List <RRset > rrSets = StreamSupport .stream (z .spliterator (), false ).collect (Collectors .toList ());
175+
176+ // there should be 3 RRsets (soa, ns, dskey)
177+ assertThat (rrSets ).hasSize (3 );
178+
179+ // assert that there is 1 SOA and it is signed
180+ List <RRset > allSoaSets =
181+ rrSets .stream ().filter (r -> r .getType () == Type .SOA ).collect (Collectors .toList ());
182+ assertThat (allSoaSets ).hasSize (1 );
183+ RRset onlySoaSet = allSoaSets .get (0 );
184+ assertThat (onlySoaSet .rrs ()).hasSize (1 );
185+ assertThat (onlySoaSet .sigs ()).hasSize (1 );
186+ // confirm that the SOA was replaced correctly
187+ assertThat (((SOARecord ) onlySoaSet .rrs ().get (0 )).getAdmin ()).isEqualTo (admin2 );
188+ // confirm that the RRSig on the SOA was replaced correctly
189+ assertThat ((onlySoaSet .sigs ().get (0 )).getSignature ())
190+ .isEqualTo ("soa2sig" .getBytes (StandardCharsets .UTF_8 ));
191+
192+ // assert that there are 2 nameservers and they are signed
193+ List <RRset > allNsSets =
194+ rrSets .stream ().filter (r -> r .getType () == Type .NS ).collect (Collectors .toList ());
195+ RRset onlyNsSet = allNsSets .get (0 );
196+ assertThat (onlyNsSet .rrs ()).hasSize (2 );
197+ assertThat (onlyNsSet .sigs ()).hasSize (1 );
198+
199+ // assert that there is 1 dskey and it is not signed
200+ List <RRset > allKeySets =
201+ rrSets .stream ().filter (r -> r .getType () == Type .DNSKEY ).collect (Collectors .toList ());
202+ RRset onlyKeySet = allKeySets .get (0 );
203+ assertThat (onlyKeySet .rrs ()).hasSize (1 );
204+ assertThat (onlyKeySet .sigs ()).hasSize (0 );
205+ }
91206}
0 commit comments