-
-
Notifications
You must be signed in to change notification settings - Fork 626
Created domain typosquatting checker #1644
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 48 commits
9d2ad83
109df58
1ef77d6
3fde001
c0eb10b
216c9ac
2349023
d345ce2
9a9fc59
62c97b4
ac3a4b9
d82deb5
381049f
55be360
43e2701
5ef1b49
3be8c44
4e81914
16ee898
a142f23
1ef772e
ccc064e
038d255
4340beb
c27794e
f38c308
ae1d7eb
ea267e0
cf26711
9cc367a
d464196
8fb46f3
6b724e3
94aed97
8375608
c57e475
b8fbcf9
f4e5968
c111cd1
79cf25b
2af0ae5
e05fbc3
5b7695e
ce40194
576be77
e82225b
2369713
a22f599
b934b24
c4502fc
5ac62ff
0ceae8f
24a45a8
3d2bab5
22f012c
67fe1b6
b37f08a
78ee5a9
7cf90cf
95fb88c
2866ee8
0f26f9d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,107 @@ | ||||||
| /* | ||||||
| Technitium DNS Server | ||||||
| Copyright (C) 2025 Shreyas Zare ([email protected]) | ||||||
| Copyright (C) 2025 Zafer Balkan ([email protected]) | ||||||
|
|
||||||
| This program is free software: you can redistribute it and/or modify | ||||||
| it under the terms of the GNU General Public License as published by | ||||||
| the Free Software Foundation, either version 3 of the License, or | ||||||
| (at your option) any later version. | ||||||
|
|
||||||
| This program is distributed in the hope that it will be useful, | ||||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
| GNU General Public License for more details. | ||||||
|
|
||||||
| You should have received a copy of the GNU General Public License | ||||||
| along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
| */ | ||||||
|
|
||||||
| using System.ComponentModel.DataAnnotations; | ||||||
| using System.IO; | ||||||
| using System.Text.Json.Serialization; | ||||||
| using System.Text.RegularExpressions; | ||||||
|
|
||||||
| namespace TyposquattingDetector | ||||||
| { | ||||||
| public sealed partial class App | ||||||
| { | ||||||
| private class Config | ||||||
| { | ||||||
| [JsonPropertyName("addExtendedDnsError")] | ||||||
| public bool AddExtendedDnsError { get; set; } = true; | ||||||
|
|
||||||
| [JsonPropertyName("allowTxtBlockingReport")] | ||||||
| public bool AllowTxtBlockingReport { get; set; } = true; | ||||||
|
|
||||||
| [JsonPropertyName("disableTlsValidation")] | ||||||
| public bool DisableTlsValidation { get; set; } = false; | ||||||
|
|
||||||
| [JsonPropertyName("enable")] | ||||||
| public bool Enable { get; set; } = true; | ||||||
|
|
||||||
| [JsonPropertyName("fuzzyMatchThreshold")] | ||||||
| [Range(75, 90, ErrorMessage = "fuzzyMatchThreshold must be between 75 and 90.")] | ||||||
| [Required(ErrorMessage = "fuzzyMatchThreshold is a required configuration property. The lower threshold means more false positives.")] | ||||||
| public int FuzzyMatchThreshold { get; set; } = 75; | ||||||
|
|
||||||
| [JsonPropertyName("customList")] | ||||||
| [RegularExpression("^(?:[a-zA-Z]:\\\\(?:[^\\\\\\/:*?\"<>|\\r\\n]+\\\\)*[^\\\\\\/:*?\"<>|\\r\\n]*|(?:\\/[^\\/\\0]+)+\\/?)$", ErrorMessage = "customList must be a valid file path with one domain per line.")] | ||||||
|
||||||
| [RegularExpression("^(?:[a-zA-Z]:\\\\(?:[^\\\\\\/:*?\"<>|\\r\\n]+\\\\)*[^\\\\\\/:*?\"<>|\\r\\n]*|(?:\\/[^\\/\\0]+)+\\/?)$", ErrorMessage = "customList must be a valid file path with one domain per line.")] | |
| [RegularExpression(@"^(?:[a-zA-Z]:\\(?:[^\\/:*?""<>|\r\n]+\\)*[^\\/:*?""<>|\r\n]*|(?:/[^/\0]+)+/?)$", ErrorMessage = "customList must be a valid file path with one domain per line.")] |
zbalkan marked this conversation as resolved.
Show resolved
Hide resolved
zbalkan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
zbalkan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| # Typosquatting Detector for Technitium DNS Server | ||
|
|
||
| A DNS security plugin that detects and blocks look-alike domains associated with phishing and brand impersonation. The plugin evaluates similarity between queried domains and a high-reputation corpus and blocks near-miss variants before resolution. | ||
|
|
||
| ## Detection model | ||
|
|
||
| The plugin builds a trusted corpus from the Majestic Million list plus an optional custom list. For each query it: | ||
|
|
||
| 1. Normalizes to the registrable domain using Public Suffix rules. | ||
| 2. Performs an O(1) Bloom filter check for known legitimate domains. | ||
| 3. Runs fuzzy similarity matching against length-adjacent candidates for unknown domains. | ||
|
|
||
| Queries above the configured similarity threshold are classified as probable typosquats and blocked. | ||
|
|
||
| ## Enforcement behavior | ||
|
|
||
| Suspicious domains receive an authoritative NXDOMAIN with SOA. Optional Extended DNS Error metadata and optional TXT blocking reports expose structured blocking details for logs and SIEM ingestion. Clean domains are not modified and resolve normally. | ||
|
|
||
| ## Configuration | ||
|
|
||
| Example configuration: | ||
|
|
||
| ```json | ||
| { | ||
| "enable": true, | ||
| "fuzzyMatchThreshold": 75, | ||
| "customList": "/path/to/custom-domains.txt", | ||
| "disableTlsValidation": false, | ||
| "updateInterval": "30d", | ||
| "allowTxtBlockingReport": true, | ||
| "addExtendedDnsError": true | ||
| } | ||
| ``` | ||
|
|
||
| Key options | ||
|
|
||
| * fuzzyMatchThreshold (75–90): main sensitivity control. Lower values detect more variants but increase false positives. | ||
| * customList: one domain per line; add organization and brand domains you want treated as trusted. | ||
| * updateInterval: controls when the Majestic list is reprocessed; rebuilds are skipped when the file hash is unchanged. | ||
| * allowTxtBlockingReport / addExtendedDnsError: control operator visibility of blocking decisions. | ||
| * disableTlsValidation: test or lab use only. | ||
|
|
||
| ## Deployment and risk considerations | ||
|
|
||
| Start with a conservative threshold (85–90) in production and observe blocks before lowering. False positives are most likely for domains visually similar to major brands but legitimate or newly emerging services. Mitigations include raising the threshold or adding the domain to the custom list. | ||
|
|
||
| This plugin is intended for recursive resolvers operated by security teams where DNS blocking is an accepted control point. Communicate expected behavior to users and support staff to avoid confusion when NXDOMAIN is enforcement rather than resolution failure. | ||
|
|
||
| ## Acknowledgements | ||
|
|
||
| Uses [Majestic Million dataset](https://majestic.com/reports/majestic-million), [Nager Public Suffix parser](https://github.com/nager/Nager.PublicSuffix), [BloomFilter.NetCore](https://github.com/vla/BloomFilter.NetCore) and [FuzzySharp](https://github.com/JakeBayer/FuzzySharp) libraries, and the Technitium DNS Server app framework. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The file path regex validation pattern attempts to validate both Windows and Unix paths but has issues. For Windows, it doesn't handle UNC paths or paths with forward slashes. For Unix, the pattern would match invalid paths. Consider using built-in Path validation methods instead of regex, or split validation by platform.