1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
//
// DNSSettings.swift
// MullvadVPN
//
// Created by pronebird on 27/04/2022.
// Copyright © 2025 Mullvad VPN AB. All rights reserved.
//
import Foundation
import MullvadTypes
import Network
/// A struct describing Mullvad DNS blocking options.
public struct DNSBlockingOptions: OptionSet, Codable, Sendable {
public let rawValue: UInt32
public static let blockAdvertising = DNSBlockingOptions(rawValue: 1 << 0)
public static let blockTracking = DNSBlockingOptions(rawValue: 1 << 1)
public static let blockMalware = DNSBlockingOptions(rawValue: 1 << 2)
public static let blockAdultContent = DNSBlockingOptions(rawValue: 1 << 3)
public static let blockGambling = DNSBlockingOptions(rawValue: 1 << 4)
public static let blockSocialMedia = DNSBlockingOptions(rawValue: 1 << 5)
public var serverAddress: IPv4Address? {
if isEmpty {
return nil
} else {
return IPv4Address("100.64.0.\(rawValue)")
}
}
public init(rawValue: UInt32) {
self.rawValue = rawValue
}
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let rawValue = try container.decode(RawValue.self)
self.init(rawValue: rawValue)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(rawValue)
}
}
/// A struct that holds DNS settings.
public struct DNSSettings: Codable, Equatable, Sendable {
/// Maximum number of allowed DNS domains.
public static let maxAllowedCustomDNSDomains = 3
/// DNS blocking options.
public var blockingOptions: DNSBlockingOptions = []
/// Enable custom DNS.
public var enableCustomDNS = false
/// Custom DNS domains.
public var customDNSDomains: [AnyIPAddress] = []
/// Effective state of the custom DNS setting.
public var effectiveEnableCustomDNS: Bool {
blockingOptions.isEmpty && enableCustomDNS && !customDNSDomains.isEmpty
}
private enum CodingKeys: String, CodingKey {
// Removed in 2022.1 in favor of `blockingOptions`
case blockAdvertising, blockTracking
// Added in 2022.1
case blockingOptions
case enableCustomDNS, customDNSDomains
}
public init() {}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
// Added in 2022.1
if let storedBlockingOptions = try container.decodeIfPresent(
DNSBlockingOptions.self,
forKey: .blockingOptions
) {
blockingOptions = storedBlockingOptions
}
if let storedBlockAdvertising = try container.decodeIfPresent(
Bool.self,
forKey: .blockAdvertising
), storedBlockAdvertising {
blockingOptions.insert(.blockAdvertising)
}
if let storedBlockTracking = try container.decodeIfPresent(
Bool.self,
forKey: .blockTracking
), storedBlockTracking {
blockingOptions.insert(.blockTracking)
}
if let storedEnableCustomDNS = try container.decodeIfPresent(
Bool.self,
forKey: .enableCustomDNS
) {
enableCustomDNS = storedEnableCustomDNS
}
if let storedCustomDNSDomains = try container.decodeIfPresent(
[AnyIPAddress].self,
forKey: .customDNSDomains
) {
customDNSDomains = storedCustomDNSDomains
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(blockingOptions, forKey: .blockingOptions)
try container.encode(enableCustomDNS, forKey: .enableCustomDNS)
try container.encode(customDNSDomains, forKey: .customDNSDomains)
}
}
|