Skip to content

Commit 8655c33

Browse files
committed
simulator/encrypted-dns: handle BindAddr; display proto in HostMsg
BindAddr, if set by the user via -iface, will be used in the various dialers. Simulation HostMsg() will display the protocol used in the simulation run (ie. DoH, DoT, DNSCrypt).
1 parent 2e1bad8 commit 8655c33

File tree

9 files changed

+86
-44
lines changed

9 files changed

+86
-44
lines changed

simulator/encdns/dnscrypt/providers/providers.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ type Provider struct {
1717
ctx context.Context
1818
sdnsStamp string
1919
c dnscrypt.Client
20+
bindIP net.IP
2021
}
2122

2223
// Providers supporting DNSCrypt.
@@ -26,33 +27,35 @@ var providers = []encdns.ProviderType{
2627
}
2728

2829
// NewRandom returns a 'random' Queryable provider.
29-
func NewRandom(ctx context.Context) encdns.Queryable {
30+
func NewRandom(ctx context.Context, bindIP net.IP) encdns.Queryable {
3031
pIdx := encdns.ProviderType(rand.Intn(len(providers)))
3132
var p encdns.Queryable
3233
switch providers[pIdx] {
3334
case encdns.ScalewayFR:
34-
p = NewScalewayFR(ctx)
35+
p = NewScalewayFR(ctx, bindIP)
3536
case encdns.Yandex:
36-
p = NewYandex(ctx)
37+
p = NewYandex(ctx, bindIP)
3738
}
3839
return p
3940
}
4041

4142
// NewYandex returns a *Provider for Yandex's DNSCrypt service.
42-
func NewYandex(ctx context.Context) *Provider {
43+
func NewYandex(ctx context.Context, bindIP net.IP) *Provider {
4344
return &Provider{
4445
ctx: ctx,
4546
sdnsStamp: "sdns://AQQAAAAAAAAAEDc3Ljg4LjguNzg6MTUzNTMg04TAccn3RmKvKszVe13MlxTUB7atNgHhrtwG1W1JYyciMi5kbnNjcnlwdC1jZXJ0LmJyb3dzZXIueWFuZGV4Lm5ldA",
4647
c: dnscrypt.Client{Net: "udp"},
48+
bindIP: bindIP,
4749
}
4850
}
4951

5052
// NewScalewayFR returns a *Provider for ScalewayFR's DNSCrypt service.
51-
func NewScalewayFR(ctx context.Context) *Provider {
53+
func NewScalewayFR(ctx context.Context, bindIP net.IP) *Provider {
5254
return &Provider{
5355
ctx: ctx,
5456
sdnsStamp: "sdns://AQcAAAAAAAAADjIxMi40Ny4yMjguMTM2IOgBuE6mBr-wusDOQ0RbsV66ZLAvo8SqMa4QY2oHkDJNHzIuZG5zY3J5cHQtY2VydC5mci5kbnNjcnlwdC5vcmc",
5557
c: dnscrypt.Client{Net: "udp"},
58+
bindIP: bindIP,
5659
}
5760
}
5861

@@ -65,6 +68,9 @@ func (p *Provider) QueryTXT(ctx context.Context, domain string) (*encdns.Respons
6568
return nil, err
6669
}
6770
d := net.Dialer{}
71+
if p.bindIP != nil {
72+
d.LocalAddr = &net.UDPAddr{IP: p.bindIP}
73+
}
6874
// Dial the actual server address obtained in ResliverInfo.
6975
conn, err := d.DialContext(p.ctx, p.c.Net, ri.ServerAddress)
7076
if err != nil {

simulator/encdns/doh/providers/cloudflare.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,18 @@ type CloudFlare struct {
1414
}
1515

1616
// NewCloudFlare returns a *CloudFlare wrapping a Provider ready to use for DoH queries.
17-
func NewCloudFlare(ctx context.Context) *CloudFlare {
17+
func NewCloudFlare(ctx context.Context, bindIP net.IP) *CloudFlare {
1818
p := CloudFlare{
1919
Provider{
2020
addr: "cloudflare-dns.com:443",
2121
queryURL: "https://cloudflare-dns.com/dns-query",
22+
bindIP: bindIP,
2223
},
2324
}
2425
d := net.Dialer{}
26+
if bindIP != nil {
27+
d.LocalAddr = &net.TCPAddr{IP: p.bindIP}
28+
}
2529
tr := &http.Transport{
2630
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
2731
return d.DialContext(ctx, "tcp", p.addr)

simulator/encdns/doh/providers/google.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,18 @@ type Google struct {
1414
}
1515

1616
// NewGoogle returns a *Google wrapping a Provider ready to use for DoH queries.
17-
func NewGoogle(ctx context.Context) *Google {
17+
func NewGoogle(ctx context.Context, bindIP net.IP) *Google {
1818
p := Google{
1919
Provider{
2020
addr: "dns.google:443",
2121
queryURL: "https://dns.google/resolve",
22+
bindIP: bindIP,
2223
},
2324
}
2425
d := net.Dialer{}
26+
if bindIP != nil {
27+
d.LocalAddr = &net.TCPAddr{IP: p.bindIP}
28+
}
2529
tr := &http.Transport{
2630
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
2731
return d.DialContext(ctx, "tcp", p.addr)

simulator/encdns/doh/providers/opendns.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,18 @@ type OpenDNS struct {
1616
}
1717

1818
// NewOpenDNS returns an *OpenDNS wrapping a Provider ready to use for DoH queries.
19-
func NewOpenDNS(ctx context.Context) *OpenDNS {
19+
func NewOpenDNS(ctx context.Context, bindIP net.IP) *OpenDNS {
2020
p := OpenDNS{
2121
Provider{
2222
addr: "doh.opendns.com:443",
2323
queryURL: "https://doh.opendns.com/dns-query",
24+
bindIP: bindIP,
2425
},
2526
}
2627
d := net.Dialer{}
28+
if bindIP != nil {
29+
d.LocalAddr = &net.TCPAddr{IP: p.bindIP}
30+
}
2731
tr := &http.Transport{
2832
DialContext: func(ctxt context.Context, network, addr string) (net.Conn, error) {
2933
return d.DialContext(ctx, "tcp", p.addr)

simulator/encdns/doh/providers/providers.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package providers
44
import (
55
"context"
66
"math/rand"
7+
"net"
78
"net/http"
89

910
"github.com/alphasoc/flightsim/simulator/encdns"
@@ -15,6 +16,7 @@ type Provider struct {
1516
addr string
1617
queryURL string
1718
client *http.Client
19+
bindIP net.IP
1820
}
1921

2022
// Providers supporting DoH.
@@ -26,18 +28,18 @@ var providers = []encdns.ProviderType{
2628
}
2729

2830
// NewRandom returns a 'random' Queryable provider.
29-
func NewRandom(ctx context.Context) encdns.Queryable {
31+
func NewRandom(ctx context.Context, bindIP net.IP) encdns.Queryable {
3032
pIdx := encdns.ProviderType(rand.Intn(len(providers)))
3133
var p encdns.Queryable
3234
switch providers[pIdx] {
3335
case encdns.GoogleProvider:
34-
p = NewGoogle(ctx)
36+
p = NewGoogle(ctx, bindIP)
3537
case encdns.CloudFlareProvider:
36-
p = NewCloudFlare(ctx)
38+
p = NewCloudFlare(ctx, bindIP)
3739
case encdns.Quad9Provider:
38-
p = NewQuad9(ctx)
40+
p = NewQuad9(ctx, bindIP)
3941
case encdns.OpenDNSProvider:
40-
p = NewOpenDNS(ctx)
42+
p = NewOpenDNS(ctx, bindIP)
4143
}
4244
return p
4345
}

simulator/encdns/doh/providers/quad9.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,18 @@ type Quad9 struct {
1414
}
1515

1616
// NewQuad9 returns a *Quad9 wrapping a Provider ready to use for DoH queries.
17-
func NewQuad9(ctx context.Context) *Quad9 {
17+
func NewQuad9(ctx context.Context, bindIP net.IP) *Quad9 {
1818
p := Quad9{
1919
Provider{
2020
addr: "dns.quad9.net:5053",
2121
queryURL: "https://dns.quad9.net:5053/dns-query",
22+
bindIP: bindIP,
2223
},
2324
}
2425
d := net.Dialer{}
26+
if bindIP != nil {
27+
d.LocalAddr = &net.TCPAddr{IP: p.bindIP}
28+
}
2529
tr := &http.Transport{
2630
DialContext: func(ctxt context.Context, network, addr string) (net.Conn, error) {
2731
return d.DialContext(ctx, "tcp", p.addr)

simulator/encdns/dot/providers/providers.go

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ import (
1212

1313
// Provider represents a DoT provider. addr and ctx are used to dial.
1414
type Provider struct {
15-
ctx context.Context
16-
addr string
15+
ctx context.Context
16+
addr string
17+
bindIP net.IP
1718
}
1819

1920
// Providers supporting DoT.
@@ -25,39 +26,42 @@ var providers = []encdns.ProviderType{
2526
}
2627

2728
// NewRandom returns a 'random' Queryable provider.
28-
func NewRandom(ctx context.Context) encdns.Queryable {
29+
func NewRandom(ctx context.Context, bindIP net.IP) encdns.Queryable {
2930
pIdx := encdns.ProviderType(rand.Intn(len(providers)))
3031
var p encdns.Queryable
3132
switch providers[pIdx] {
3233
case encdns.GoogleProvider:
33-
p = NewGoogle(ctx)
34+
p = NewGoogle(ctx, bindIP)
3435
case encdns.CloudFlareProvider:
35-
p = NewCloudFlare(ctx)
36+
p = NewCloudFlare(ctx, bindIP)
3637
case encdns.Quad9Provider:
37-
p = NewQuad9(ctx)
38+
p = NewQuad9(ctx, bindIP)
3839
}
3940
return p
4041
}
4142

4243
// NewGoogle returns a *Provider for Google's DoT service.
43-
func NewGoogle(ctx context.Context) *Provider {
44-
return &Provider{ctx: ctx, addr: "dns.google:853"}
44+
func NewGoogle(ctx context.Context, bindIP net.IP) *Provider {
45+
return &Provider{ctx: ctx, addr: "dns.google:853", bindIP: bindIP}
4546
}
4647

4748
// NewGoogle returns a *Provider tied for CloudFlare's DoT service.
48-
func NewCloudFlare(ctx context.Context) *Provider {
49-
return &Provider{ctx: ctx, addr: "1dot1dot1dot1.cloudflare-dns.com:853"}
49+
func NewCloudFlare(ctx context.Context, bindIP net.IP) *Provider {
50+
return &Provider{ctx: ctx, addr: "1dot1dot1dot1.cloudflare-dns.com:853", bindIP: bindIP}
5051
}
5152

5253
// NewGoogle returns a *Provider for Quad9's DoT service.
53-
func NewQuad9(ctx context.Context) *Provider {
54-
return &Provider{ctx: ctx, addr: "dns.quad9.net:853"}
54+
func NewQuad9(ctx context.Context, bindIP net.IP) *Provider {
55+
return &Provider{ctx: ctx, addr: "dns.quad9.net:853", bindIP: bindIP}
5556
}
5657

5758
// QueryTXT performs a DoT TXT lookup using Provider p, and returns a *encdns.Response and
5859
// an error.
5960
func (p *Provider) QueryTXT(ctx context.Context, domain string) (*encdns.Response, error) {
6061
d := tls.Dialer{}
62+
if p.bindIP != nil {
63+
d.NetDialer = &net.Dialer{LocalAddr: &net.TCPAddr{IP: p.bindIP}}
64+
}
6165
r := &net.Resolver{
6266
PreferGo: true,
6367
Dial: func(ctx context.Context, network, addr string) (net.Conn, error) {

simulator/encdns/encdns.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ type Protocol int
1515

1616
// Supported DNS protocols.
1717
const (
18-
Random Protocol = iota
19-
DoH
18+
DoH = iota
2019
DoT
2120
DNSCrypt
2221
)
@@ -25,8 +24,7 @@ var protocolMap map[string]Protocol = map[string]Protocol{"doh": DoH, "dot": DoT
2524

2625
// RandomProtocol returns a random supported Protocol.
2726
func RandomProtocol() Protocol {
28-
// Account for the fact that Protocol(0) == Random.
29-
return Protocol(rand.Intn(len(protocolMap)) + 1)
27+
return Protocol(rand.Intn(len(protocolMap)))
3028
}
3129

3230
// A generic response wrapper for DoH/DoT, etc.

simulator/encrypted-dns.go

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package simulator
33
import (
44
"context"
55
"fmt"
6+
"net"
67
"strings"
78
"time"
89

@@ -28,23 +29,42 @@ func NewEncryptedDNS() *EncryptedDNS {
2829
}
2930

3031
func (s *EncryptedDNS) Init(bind BindAddr) error {
31-
// TODO: along with issues/39, bind if iface specififed.
3232
s.bind = bind
3333
return nil
3434
}
3535

3636
func (EncryptedDNS) Cleanup() {
3737
}
3838

39+
// HostMsg implements the HostMsgFormatter interface, returning a custom host message
40+
// string to be output by the run command.
41+
func (s *EncryptedDNS) HostMsg(host string) string {
42+
var protoStr string
43+
switch s.Proto {
44+
case encdns.DoH:
45+
protoStr = "DNS-over-HTTPS"
46+
case encdns.DoT:
47+
protoStr = "DNS-over-TLS"
48+
case encdns.DNSCrypt:
49+
protoStr = "DNSCrypt"
50+
}
51+
return fmt.Sprintf("Simulating Encrypted DNS (%s) via *.%s", protoStr, host)
52+
}
53+
3954
// randomProvider returns a random Protocol p Provider.
40-
func randomProvider(ctx context.Context, p encdns.Protocol) encdns.Queryable {
41-
switch p {
55+
func (s *EncryptedDNS) randomProvider(ctx context.Context) encdns.Queryable {
56+
// If the user has set a bind interface via the -iface flag, have providers use it.
57+
var bindIP net.IP
58+
if s.bind.UserSet {
59+
bindIP = s.bind.Addr
60+
}
61+
switch s.Proto {
4262
case encdns.DoH:
43-
return dohproviders.NewRandom(ctx)
63+
return dohproviders.NewRandom(ctx, bindIP)
4464
case encdns.DoT:
45-
return dotproviders.NewRandom(ctx)
65+
return dotproviders.NewRandom(ctx, bindIP)
4666
case encdns.DNSCrypt:
47-
return dnscryptproviders.NewRandom(ctx)
67+
return dnscryptproviders.NewRandom(ctx, bindIP)
4868
default:
4969
return nil
5070
}
@@ -53,12 +73,8 @@ func randomProvider(ctx context.Context, p encdns.Protocol) encdns.Queryable {
5373
// Simulate lookups for txt records for give host.
5474
func (s *EncryptedDNS) Simulate(ctx context.Context, host string) error {
5575
host = utils.FQDN(host)
56-
// Select random Protocol (DoH/DoT/etc) if not specified on the commandline.
57-
if s.Proto == encdns.Random {
58-
s.Proto = encdns.RandomProtocol()
59-
}
6076
// Select a random Provider to be used in this simulation.
61-
p := randomProvider(ctx, s.Proto)
77+
p := s.randomProvider(ctx)
6278
if p == nil {
6379
return fmt.Errorf("invalid DNS protocol: unable to select provider")
6480
}
@@ -78,7 +94,6 @@ func (s *EncryptedDNS) Simulate(ctx context.Context, host string) error {
7894

7995
// Ignore timeout. In case of DoH, when err != nil, resp.Body has already been
8096
// closed.
81-
// TODO: Need timeout/dial error check from issues/39
8297
if err != nil {
8398
if isSoftError(err) {
8499
continue
@@ -111,7 +126,6 @@ func (s *EncryptedDNS) Simulate(ctx context.Context, host string) error {
111126
// TODO: If that's not the case, we can add more comprehensive response parsing.
112127
case encdns.DNSCrypt:
113128
dnsCryptResp, err := resp.DNSCryptResponse()
114-
fmt.Println(dnsCryptResp)
115129
if err != nil {
116130
return fmt.Errorf("failed extracting DNSCrypt response: %v", err)
117131
}
@@ -133,7 +147,9 @@ func (s *EncryptedDNS) Hosts(scope string, size int) ([]string, error) {
133147
}
134148
s.Proto = proto
135149
} else {
136-
s.Proto = encdns.Random
150+
// Select random Protocol (DoH/DoT/etc) if not specified on the commandline.
151+
// NOTE: doing this from Hosts() to display in HostMsg().
152+
s.Proto = encdns.RandomProtocol()
137153
}
138154
return []string{"sandbox.alphasoc.xyz"}, nil
139155
}

0 commit comments

Comments
 (0)