krz/domain-dig
an ios app for DNS & SSL analysis
clone: git clone https://gitbay.org/krz/domain-dig.git
v1.4.0: DomainDig/Models.swift · raw
1import Foundation
2
3// MARK: - DNS Models
4
5enum DNSRecordType: String, CaseIterable, Codable {
6 case A
7 case AAAA
8 case MX
9 case NS
10 case TXT
11 case CNAME
12 case SOA
13 case SRV
14 case CAA
15 case DS
16
17 var queryType: Int {
18 switch self {
19 case .A: return 1
20 case .AAAA: return 28
21 case .MX: return 15
22 case .NS: return 2
23 case .TXT: return 16
24 case .CNAME: return 5
25 case .SOA: return 6
26 case .SRV: return 33
27 case .CAA: return 257
28 case .DS: return 43
29 }
30 }
31
32 var usesRawDataValue: Bool {
33 switch self {
34 case .TXT, .SOA, .DS:
35 return true
36 default:
37 return false
38 }
39 }
40}
41
42struct DNSRecord: Identifiable, Codable {
43 var id = UUID()
44 let value: String
45 let ttl: Int
46}
47
48struct DNSSection: Identifiable, Codable {
49 var id = UUID()
50 let recordType: DNSRecordType
51 var records: [DNSRecord]
52 var wildcardRecords: [DNSRecord] = []
53 var dnssecSigned: Bool?
54 var error: String?
55}
56
57// MARK: - SSL Models
58
59struct SSLCertificateInfo: Codable {
60 struct CertChainEntry: Codable {
61 let subject: String
62 let issuer: String
63 }
64
65 let commonName: String
66 let subjectAltNames: [String]
67 let issuer: String
68 let validFrom: Date
69 let validUntil: Date
70 let daysUntilExpiry: Int
71 let chainDepth: Int
72 let tlsVersion: String?
73 let cipherSuite: String?
74 let chain: [CertChainEntry]
75
76 init(
77 commonName: String,
78 subjectAltNames: [String],
79 issuer: String,
80 validFrom: Date,
81 validUntil: Date,
82 daysUntilExpiry: Int,
83 chainDepth: Int,
84 tlsVersion: String? = nil,
85 cipherSuite: String? = nil,
86 chain: [CertChainEntry] = []
87 ) {
88 self.commonName = commonName
89 self.subjectAltNames = subjectAltNames
90 self.issuer = issuer
91 self.validFrom = validFrom
92 self.validUntil = validUntil
93 self.daysUntilExpiry = daysUntilExpiry
94 self.chainDepth = chainDepth
95 self.tlsVersion = tlsVersion
96 self.cipherSuite = cipherSuite
97 self.chain = chain
98 }
99
100 init(from decoder: Decoder) throws {
101 let container = try decoder.container(keyedBy: CodingKeys.self)
102 commonName = try container.decode(String.self, forKey: .commonName)
103 subjectAltNames = try container.decode([String].self, forKey: .subjectAltNames)
104 issuer = try container.decode(String.self, forKey: .issuer)
105 validFrom = try container.decode(Date.self, forKey: .validFrom)
106 validUntil = try container.decode(Date.self, forKey: .validUntil)
107 daysUntilExpiry = try container.decode(Int.self, forKey: .daysUntilExpiry)
108 chainDepth = try container.decode(Int.self, forKey: .chainDepth)
109 tlsVersion = try container.decodeIfPresent(String.self, forKey: .tlsVersion)
110 cipherSuite = try container.decodeIfPresent(String.self, forKey: .cipherSuite)
111 chain = try container.decodeIfPresent([CertChainEntry].self, forKey: .chain) ?? []
112 }
113}
114
115// MARK: - HTTP Headers Models
116
117struct HTTPHeader: Identifiable, Codable {
118 var id = UUID()
119 let name: String
120 let value: String
121
122 static let securityHeaders: Set<String> = [
123 "strict-transport-security",
124 "x-frame-options",
125 "x-content-type-options",
126 "content-security-policy",
127 "referrer-policy"
128 ]
129
130 var isSecurityHeader: Bool {
131 Self.securityHeaders.contains(name.lowercased())
132 }
133}
134
135// MARK: - Reachability Models
136
137struct PortReachability: Identifiable, Codable {
138 var id = UUID()
139 let port: UInt16
140 let reachable: Bool
141 let latencyMs: Int?
142}
143
144// MARK: - IP Geolocation Models
145
146struct IPGeolocation: Codable {
147 let ip: String
148 let city: String?
149 let region: String?
150 let country_name: String?
151 let org: String?
152 let latitude: Double?
153 let longitude: Double?
154}
155
156// MARK: - Email Security Models
157
158struct EmailSecurityResult: Codable {
159 let spf: EmailSecurityRecord
160 let dmarc: EmailSecurityRecord
161 let dkim: EmailSecurityRecord
162}
163
164struct EmailSecurityRecord: Codable {
165 let found: Bool
166 let value: String?
167}
168
169// MARK: - Redirect Chain Models
170
171struct RedirectHop: Identifiable, Codable {
172 var id = UUID()
173 let stepNumber: Int
174 let statusCode: Int
175 let url: String
176 let isFinal: Bool
177}
178
179// MARK: - Port Scan Models
180
181struct PortScanResult: Identifiable, Codable {
182 var id = UUID()
183 let port: UInt16
184 let service: String
185 let open: Bool
186}
187
188// MARK: - History Models
189
190struct HistoryEntry: Identifiable, Codable {
191 var id = UUID()
192 let domain: String
193 let timestamp: Date
194 let dnsSections: [DNSSection]
195 let sslInfo: SSLCertificateInfo?
196 let httpHeaders: [HTTPHeader]
197 let reachabilityResults: [PortReachability]
198 let ipGeolocation: IPGeolocation?
199 var emailSecurity: EmailSecurityResult?
200 var ptrRecord: String?
201 var redirectChain: [RedirectHop]
202 var portScanResults: [PortScanResult]
203 var hstsPreloaded: Bool?
204
205 init(domain: String, timestamp: Date, dnsSections: [DNSSection],
206 sslInfo: SSLCertificateInfo?, httpHeaders: [HTTPHeader],
207 reachabilityResults: [PortReachability], ipGeolocation: IPGeolocation?,
208 emailSecurity: EmailSecurityResult? = nil, ptrRecord: String? = nil,
209 redirectChain: [RedirectHop] = [], portScanResults: [PortScanResult] = [],
210 hstsPreloaded: Bool? = nil) {
211 self.domain = domain
212 self.timestamp = timestamp
213 self.dnsSections = dnsSections
214 self.sslInfo = sslInfo
215 self.httpHeaders = httpHeaders
216 self.reachabilityResults = reachabilityResults
217 self.ipGeolocation = ipGeolocation
218 self.emailSecurity = emailSecurity
219 self.ptrRecord = ptrRecord
220 self.redirectChain = redirectChain
221 self.portScanResults = portScanResults
222 self.hstsPreloaded = hstsPreloaded
223 }
224
225 init(from decoder: Decoder) throws {
226 let container = try decoder.container(keyedBy: CodingKeys.self)
227 id = try container.decodeIfPresent(UUID.self, forKey: .id) ?? UUID()
228 domain = try container.decode(String.self, forKey: .domain)
229 timestamp = try container.decode(Date.self, forKey: .timestamp)
230 dnsSections = try container.decode([DNSSection].self, forKey: .dnsSections)
231 sslInfo = try container.decodeIfPresent(SSLCertificateInfo.self, forKey: .sslInfo)
232 httpHeaders = try container.decode([HTTPHeader].self, forKey: .httpHeaders)
233 reachabilityResults = try container.decode([PortReachability].self, forKey: .reachabilityResults)
234 ipGeolocation = try container.decodeIfPresent(IPGeolocation.self, forKey: .ipGeolocation)
235 emailSecurity = try container.decodeIfPresent(EmailSecurityResult.self, forKey: .emailSecurity)
236 ptrRecord = try container.decodeIfPresent(String.self, forKey: .ptrRecord)
237 redirectChain = try container.decodeIfPresent([RedirectHop].self, forKey: .redirectChain) ?? []
238 portScanResults = try container.decodeIfPresent([PortScanResult].self, forKey: .portScanResults) ?? []
239 hstsPreloaded = try container.decodeIfPresent(Bool.self, forKey: .hstsPreloaded)
240 }
241}
242
243// MARK: - Cloudflare DNS-over-HTTPS Response
244
245struct CloudflareDNSResponse: Decodable {
246 let Status: Int
247 let Answer: [CloudflareDNSAnswer]?
248
249 struct CloudflareDNSAnswer: Decodable {
250 let name: String
251 let type: Int
252 let TTL: Int
253 let data: String
254 }
255}