Просмотр исходного кода

Fix DNS resolver "additional answers" logic

- Guard against nil pointer dereference
- Loop until all additional answers are drained
Rod Hynes 3 лет назад
Родитель
Сommit
cb4e5e24dc
1 измененных файлов с 15 добавлено и 5 удалено
  1. 15 5
      psiphon/common/resolver/resolver.go

+ 15 - 5
psiphon/common/resolver/resolver.go

@@ -838,11 +838,21 @@ func (r *Resolver) ResolveIP(
 	// arrived concurrent with the first answer. This receive avoids a race
 	// arrived concurrent with the first answer. This receive avoids a race
 	// condition where inFlight may now be 0, with additional answers
 	// condition where inFlight may now be 0, with additional answers
 	// enqueued, in which case the following await branch is not taken.
 	// enqueued, in which case the following await branch is not taken.
-	select {
-	case nextAnswer := <-answerChan:
-		result.IPs = append(result.IPs, nextAnswer.IPs...)
-		result.TTLs = append(result.TTLs, nextAnswer.TTLs...)
-	default:
+	//
+	// It's possible for the attempts loop to exit with no received answer due
+	// to timeouts or cancellation while, concurrently, an answer is sent to
+	// the channel. In this case, when result == nil, we ignore the answers
+	// and leave this as a failed resolve.
+	if result != nil {
+		for loop := true; loop; {
+			select {
+			case nextAnswer := <-answerChan:
+				result.IPs = append(result.IPs, nextAnswer.IPs...)
+				result.TTLs = append(result.TTLs, nextAnswer.TTLs...)
+			default:
+				loop = false
+			}
+		}
 	}
 	}
 
 
 	// When we have an answer, await -- for a short time,
 	// When we have an answer, await -- for a short time,