@@ -2,14 +2,15 @@ package zeroconf
22
33import (
44 "context"
5+ "fmt"
56 "log"
67 "testing"
78 "time"
89
910 "github.com/pkg/errors"
1011)
1112
12- var (
13+ const (
1314 mdnsName = "test--xxxxxxxxxxxx"
1415 mdnsService = "_test--xxxx._tcp"
1516 mdnsSubtype = "_test--xxxx._tcp,_fancy"
@@ -163,4 +164,70 @@ func TestSubtype(t *testing.T) {
163164 t .Fatalf ("Expected port is %d, but got %d" , mdnsPort , result .Port )
164165 }
165166 })
167+
168+ t .Run ("DoS protection" , func (t * testing.T ) {
169+ origMaxSentEntries := maxSentEntries
170+ maxSentEntries = 10
171+ defer func () {
172+ time .Sleep (100 * time .Millisecond ) // give the mainloop some time to shut down
173+ maxSentEntries = origMaxSentEntries
174+ }()
175+
176+ ctx , cancel := context .WithTimeout (context .Background (), 10 * time .Second )
177+ defer cancel ()
178+
179+ const firstName = mdnsName
180+
181+ go startMDNS (ctx , mdnsPort , firstName , mdnsSubtype , mdnsDomain )
182+ time .Sleep (time .Second )
183+
184+ resolver , err := NewResolver (nil )
185+ if err != nil {
186+ t .Fatalf ("Expected create resolver success, but got %v" , err )
187+ }
188+ entries := make (chan * ServiceEntry , maxSentEntries + 1 )
189+ received := make (chan * ServiceEntry , 10 )
190+ go func () {
191+ for {
192+ select {
193+ case entry := <- entries :
194+ if entry .Instance == firstName {
195+ received <- entry
196+ }
197+ case <- ctx .Done ():
198+ return
199+ }
200+ }
201+ }()
202+ if err := resolver .Browse (ctx , mdnsService , mdnsDomain , entries ); err != nil {
203+ t .Fatalf ("Expected browse success, but got %v" , err )
204+ }
205+ select {
206+ case <- received :
207+ case <- time .NewTimer (time .Second ).C :
208+ t .Fatal ("expected to discover service" )
209+ }
210+
211+ for i := 1 ; i < maxSentEntries ; i ++ {
212+ go startMDNS (ctx , mdnsPort , fmt .Sprintf ("%s-%d" , mdnsName , i ), mdnsSubtype , mdnsDomain )
213+ }
214+ time .Sleep (time .Second )
215+
216+ select {
217+ case entry := <- entries :
218+ t .Fatalf ("didn't expect to receive an entry, got %v" , entry )
219+ default :
220+ }
221+
222+ // Announcing this service will cause the map to overflow.
223+ go startMDNS (ctx , mdnsPort , fmt .Sprintf ("%s-%d" , mdnsName , maxSentEntries ), mdnsSubtype , mdnsDomain )
224+
225+ // wait for a re-announcement of the firstName service
226+ select {
227+ case <- received :
228+ cancel ()
229+ case <- ctx .Done ():
230+ t .Fatal ("expected to discover service" )
231+ }
232+ })
166233}
0 commit comments