@@ -12,6 +12,11 @@ public struct DNSModule: Module, BuildableType, Hashable, Codable {
1212 case tls( hostname: String )
1313 }
1414
15+ public enum DomainPolicy : Hashable , Codable , Sendable {
16+ case search
17+ case match
18+ }
19+
1520 public static let moduleType = ModuleType ( " DNS " )
1621
1722 public let id : UniqueID
@@ -24,6 +29,8 @@ public struct DNSModule: Module, BuildableType, Hashable, Codable {
2429
2530 public let searchDomains : [ Address ] ?
2631
32+ public let domainPolicy : DomainPolicy ?
33+
2734 public let routesThroughVPN : Bool ?
2835
2936 fileprivate init (
@@ -32,13 +39,15 @@ public struct DNSModule: Module, BuildableType, Hashable, Codable {
3239 servers: [ Address ] ,
3340 domainName: Address ? ,
3441 searchDomains: [ Address ] ? ,
42+ domainPolicy: DomainPolicy ? ,
3543 routesThroughVPN: Bool ?
3644 ) {
3745 self . id = id
3846 self . protocolType = protocolType
3947 self . servers = servers
4048 self . domainName = domainName
4149 self . searchDomains = searchDomains
50+ self . domainPolicy = domainPolicy
4251 self . routesThroughVPN = routesThroughVPN
4352 }
4453
@@ -50,17 +59,29 @@ public struct DNSModule: Module, BuildableType, Hashable, Codable {
5059 switch protocolType {
5160 case . cleartext:
5261 break
53-
5462 case . https( let url) :
5563 builder. protocolType = . https
5664 builder. dohURL = url. absoluteString
57-
5865 case . tls( let hostname) :
5966 builder. protocolType = . tls
6067 builder. dotHostname = hostname
6168 }
62- builder. domainName = domainName? . rawValue
63- builder. searchDomains = searchDomains? . map ( \. rawValue)
69+ if let domainName {
70+ builder. isFirstDomainPrimary = true
71+ if let searchDomains {
72+ if domainName == searchDomains. first {
73+ builder. domains = searchDomains. map ( \. rawValue)
74+ } else {
75+ builder. domains = [ domainName. rawValue] + searchDomains. map ( \. rawValue)
76+ }
77+ } else {
78+ builder. domains = [ domainName. rawValue]
79+ }
80+ } else if let searchDomains {
81+ builder. isFirstDomainPrimary = false
82+ builder. domains = searchDomains. map ( \. rawValue)
83+ }
84+ builder. domainPolicy = domainPolicy
6485 builder. routesThroughVPN = routesThroughVPN
6586 return builder
6687 }
@@ -78,9 +99,11 @@ extension DNSModule {
7899
79100 public var dotHostname : String
80101
81- public var domainName : String ?
102+ public var domains : [ String ] ?
103+
104+ public var domainPolicy : DomainPolicy ?
82105
83- public var searchDomains : [ String ] ?
106+ public var isFirstDomainPrimary : Bool
84107
85108 public var routesThroughVPN : Bool ?
86109
@@ -94,17 +117,19 @@ extension DNSModule {
94117 servers: [ String ] = [ ] ,
95118 dohURL: String = " " ,
96119 dotHostname: String = " " ,
97- domainName: String ? = nil ,
98- searchDomains: [ String ] ? = nil ,
120+ domains: [ String ] ? = nil ,
121+ domainPolicy: DomainPolicy ? = nil ,
122+ isFirstDomainPrimary: Bool = true ,
99123 routesThroughVPN: Bool ? = nil
100124 ) {
101125 self . id = id
102126 self . protocolType = protocolType
103127 self . servers = servers
104128 self . dohURL = dohURL
105129 self . dotHostname = dotHostname
106- self . domainName = domainName
107- self . searchDomains = searchDomains
130+ self . domains = domains
131+ self . domainPolicy = domainPolicy
132+ self . isFirstDomainPrimary = isFirstDomainPrimary
108133 self . routesThroughVPN = routesThroughVPN
109134 }
110135
@@ -118,25 +143,15 @@ extension DNSModule {
118143 }
119144 return addr
120145 }
121- let validDomainName = try domainName . flatMap {
146+ let validDomains = try domains ? . compactMap {
122147 guard !$0. isEmpty else {
123148 return nil as Address ?
124149 }
125150 guard let addr = Address ( rawValue: $0) , !addr. isIPAddress else {
126- throw PartoutError . invalidFields ( [ " domainName " : $0] )
151+ throw PartoutError . invalidFields ( [ " domains " : $0] )
127152 }
128153 return addr
129154 }
130- let validSearchDomains = try searchDomains? . compactMap {
131- guard !$0. isEmpty else {
132- return nil as Address ?
133- }
134- guard let addr = Address ( rawValue: $0) , !addr. isIPAddress else {
135- throw PartoutError . invalidFields ( [ " searchDomains " : $0] )
136- }
137- return addr
138- }
139-
140155 let validProtocolType : ProtocolType
141156 switch protocolType {
142157 case . cleartext:
@@ -158,8 +173,9 @@ extension DNSModule {
158173 id: id,
159174 protocolType: validProtocolType,
160175 servers: validServers,
161- domainName: validDomainName,
162- searchDomains: validSearchDomains,
176+ domainName: isFirstDomainPrimary ? validDomains? . first : nil ,
177+ searchDomains: validDomains,
178+ domainPolicy: domainPolicy,
163179 routesThroughVPN: routesThroughVPN
164180 )
165181 }
0 commit comments