diff --git a/client_info.go b/client_info.go index f32526a..05d2910 100644 --- a/client_info.go +++ b/client_info.go @@ -5,10 +5,11 @@ type ClientInfoCtxKey struct{} // ClientInfo represents ctrld's clients information. type ClientInfo struct { - Mac string - IP string - Hostname string - Self bool + Mac string + IP string + Hostname string + Self bool + ClientIDPref string } // LeaseFileFormat specifies the format of DHCP lease file. diff --git a/cmd/cli/dns_proxy.go b/cmd/cli/dns_proxy.go index e2477f2..26f3931 100644 --- a/cmd/cli/dns_proxy.go +++ b/cmd/cli/dns_proxy.go @@ -67,6 +67,7 @@ func (p *prog) serveDNS(listenerNum string) error { reqId := requestID() remoteIP, _, _ := net.SplitHostPort(w.RemoteAddr().String()) ci := p.getClientInfo(remoteIP, m) + ci.ClientIDPref = p.cfg.Service.ClientIDPref stripClientSubnet(m) remoteAddr := spoofRemoteAddr(w.RemoteAddr(), ci) fmtSrcToDest := fmtRemoteToLocal(listenerNum, remoteAddr.String(), w.LocalAddr().String()) diff --git a/config.go b/config.go index 1bd9043..d3509be 100644 --- a/config.go +++ b/config.go @@ -193,6 +193,7 @@ type ServiceConfig struct { DiscoverDHCP *bool `mapstructure:"discover_dhcp" toml:"discover_dhcp,omitempty"` DiscoverPtr *bool `mapstructure:"discover_ptr" toml:"discover_ptr,omitempty"` DiscoverHosts *bool `mapstructure:"discover_hosts" toml:"discover_hosts,omitempty"` + ClientIDPref string `mapstructure:"client_id_preference" toml:"client_id_preference,omitempty" validate:"omitempty,oneof=host mac"` Daemon bool `mapstructure:"-" toml:"-"` AllocateIP bool `mapstructure:"-" toml:"-"` } diff --git a/config_test.go b/config_test.go index 4123f00..ff20bc2 100644 --- a/config_test.go +++ b/config_test.go @@ -101,6 +101,7 @@ func TestConfigValidation(t *testing.T) { {"lease file format required if lease file exist", configWithExistedLeaseFile(t), true}, {"invalid lease file format", configWithInvalidLeaseFileFormat(t), true}, {"invalid doh/doh3 endpoint", configWithInvalidDoHEndpoint(t), true}, + {"invalid client id pref", configWithInvalidClientIDPref(t), true}, } for _, tc := range tests { @@ -238,3 +239,9 @@ func configWithInvalidDoHEndpoint(t *testing.T) *ctrld.Config { cfg.Upstream["0"].Type = ctrld.ResolverTypeDOH return cfg } + +func configWithInvalidClientIDPref(t *testing.T) *ctrld.Config { + cfg := defaultConfig(t) + cfg.Service.ClientIDPref = "foo" + return cfg +} diff --git a/docs/config.md b/docs/config.md index bc0ead2..266c17a 100644 --- a/docs/config.md +++ b/docs/config.md @@ -215,6 +215,17 @@ DHCP leases file format. - Valid values: `dnsmasq`, `isc-dhcp` - Default: "" +### client_id_preference +Decide how client ID has is generated. + +If `host` -> client id will be a `hash(hostname)`. +If `mac` -> client id will be `hash(mac)`. + +- Type: string +- Required: no +- Valid values: `mac`, `host` +- Default: "" + ## Upstream The `[upstream]` section specifies the DNS upstream servers that `ctrld` will forward DNS requests to. diff --git a/doh.go b/doh.go index 96f8051..25ed2cb 100644 --- a/doh.go +++ b/doh.go @@ -18,11 +18,12 @@ import ( ) const ( - dohMacHeader = "x-cd-mac" - dohIPHeader = "x-cd-ip" - dohHostHeader = "x-cd-host" - dohOsHeader = "x-cd-os" - headerApplicationDNS = "application/dns-message" + dohMacHeader = "x-cd-mac" + dohIPHeader = "x-cd-ip" + dohHostHeader = "x-cd-host" + dohOsHeader = "x-cd-os" + dohClientIDPrefHeader = "x-cd-cpref" + headerApplicationDNS = "application/dns-message" ) // EncodeOsNameMap provides mapping from OS name to a shorter string, used for encoding x-cd-os value. @@ -181,6 +182,12 @@ func addControlDHeaders(req *http.Request, ci *ClientInfo) { if ci.Self { req.Header.Set(dohOsHeader, dohOsHeaderValue()) } + switch ci.ClientIDPref { + case "mac": + req.Header.Set(dohClientIDPrefHeader, "1") + case "host": + req.Header.Set(dohClientIDPrefHeader, "2") + } } // addNextDNSHeaders set DoH/Doh3 HTTP request headers for nextdns upstream.