1
1
package conf
2
2
3
3
import (
4
+ "bufio"
4
5
"encoding/json"
6
+ "os"
7
+ "path/filepath"
8
+ "runtime"
5
9
"sort"
6
10
"strings"
7
11
@@ -192,6 +196,7 @@ type DNSConfig struct {
192
196
DisableCache bool `json:"disableCache"`
193
197
DisableFallback bool `json:"disableFallback"`
194
198
DisableFallbackIfMatch bool `json:"disableFallbackIfMatch"`
199
+ UseSystemHosts bool `json:"useSystemHosts"`
195
200
}
196
201
197
202
type HostAddress struct {
@@ -413,6 +418,15 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
413
418
}
414
419
config .StaticHosts = append (config .StaticHosts , staticHosts ... )
415
420
}
421
+ if c .UseSystemHosts {
422
+ systemHosts , err := readSystemHosts ()
423
+ if err != nil {
424
+ return nil , errors .New ("failed to read system hosts" ).Base (err )
425
+ }
426
+ for domain , ips := range systemHosts {
427
+ config .StaticHosts = append (config .StaticHosts , & dns.Config_HostMapping {Ip : ips , Domain : domain , Type : dns .DomainMatchingType_Full })
428
+ }
429
+ }
416
430
417
431
return config , nil
418
432
}
@@ -431,3 +445,85 @@ func resolveQueryStrategy(queryStrategy string) dns.QueryStrategy {
431
445
return dns .QueryStrategy_USE_IP
432
446
}
433
447
}
448
+
449
+ func readSystemHosts () (map [string ][][]byte , error ) {
450
+ var hostsPath string
451
+ switch runtime .GOOS {
452
+ case "windows" :
453
+ hostsPath = filepath .Join (os .Getenv ("SystemRoot" ), "System32" , "drivers" , "etc" , "hosts" )
454
+ default :
455
+ hostsPath = "/etc/hosts"
456
+ }
457
+
458
+ file , err := os .Open (hostsPath )
459
+ if err != nil {
460
+ return nil , err
461
+ }
462
+ defer file .Close ()
463
+
464
+ hostsMap := make (map [string ][][]byte )
465
+ scanner := bufio .NewScanner (file )
466
+ for scanner .Scan () {
467
+ line := strings .TrimSpace (scanner .Text ())
468
+ if i := strings .IndexByte (line , '#' ); i >= 0 {
469
+ // Discard comments.
470
+ line = line [0 :i ]
471
+ }
472
+ f := getFields (line )
473
+ if len (f ) < 2 {
474
+ continue
475
+ }
476
+ addr := net .ParseAddress (f [0 ])
477
+ if addr .Family ().IsDomain () {
478
+ continue
479
+ }
480
+ ip := addr .IP ()
481
+ for i := 1 ; i < len (f ); i ++ {
482
+ domain := strings .TrimSuffix (f [i ], "." )
483
+ domain = strings .ToLower (domain )
484
+ if v , ok := hostsMap [domain ]; ok {
485
+ hostsMap [domain ] = append (v , ip )
486
+ } else {
487
+ hostsMap [domain ] = [][]byte {ip }
488
+ }
489
+ }
490
+ }
491
+ if err := scanner .Err (); err != nil {
492
+ return nil , err
493
+ }
494
+ return hostsMap , nil
495
+ }
496
+
497
+ func getFields (s string ) []string { return splitAtBytes (s , " \r \t \n " ) }
498
+
499
+ // Count occurrences in s of any bytes in t.
500
+ func countAnyByte (s string , t string ) int {
501
+ n := 0
502
+ for i := 0 ; i < len (s ); i ++ {
503
+ if strings .IndexByte (t , s [i ]) >= 0 {
504
+ n ++
505
+ }
506
+ }
507
+ return n
508
+ }
509
+
510
+ // Split s at any bytes in t.
511
+ func splitAtBytes (s string , t string ) []string {
512
+ a := make ([]string , 1 + countAnyByte (s , t ))
513
+ n := 0
514
+ last := 0
515
+ for i := 0 ; i < len (s ); i ++ {
516
+ if strings .IndexByte (t , s [i ]) >= 0 {
517
+ if last < i {
518
+ a [n ] = s [last :i ]
519
+ n ++
520
+ }
521
+ last = i + 1
522
+ }
523
+ }
524
+ if last < len (s ) {
525
+ a [n ] = s [last :]
526
+ n ++
527
+ }
528
+ return a [0 :n ]
529
+ }
0 commit comments