Skip to content

Instantly share code, notes, and snippets.

@Orlys
Created October 3, 2022 06:55
Show Gist options
  • Save Orlys/2de699ce6125719f1ec37a878976025e to your computer and use it in GitHub Desktop.
Save Orlys/2de699ce6125719f1ec37a878976025e to your computer and use it in GitHub Desktop.
域名黑名單(DNSBL)與垃圾訊息(Spam)檢查
//
// Copyright 2022 Orlys Ma
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
namespace AntiSpam
{
using DnsClient;
using DnsClient.Protocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
/// <summary>
/// <see href="https://www.spamhaus.org/faq/section/DNSBL%20Usage">Spamhaus' DBL</see> 服務。
/// </summary>
public class DomainSpamhausService
{
private readonly LookupClient _lookupClient = new LookupClient(/*上層伺服器不可為公用名稱伺服器, 例如 1.1.1.1 及 8.8.8.8 */);
/// <summary>
/// 域名是否存在於域名黑名單(DNSBL)中。
/// </summary>
/// <param name="domain"></param>
/// <returns></returns>
public async Task<bool> IsBlacklisted(string domain)
{
// Spamhaus DNSBL 服務
var response = await _lookupClient
.QueryAsync(domain + ".dbl.spamhaus.org", QueryType.A)
.ConfigureAwait(false)
;
var answer = response.Answers.OfType<ARecord>().FirstOrDefault();
if (answer is null)
{
// 找不到視同通過黑名單。
return false;
}
var address = answer.Address;
return s_blacklistedAddresses.Contains(address);
}
private static HashSet<IPAddress> s_blacklistedAddresses = new(){
IPAddress.Parse("127.0.1.2"),
IPAddress.Parse("127.0.1.4"),
IPAddress.Parse("127.0.1.5"),
IPAddress.Parse("127.0.1.6"),
IPAddress.Parse("127.0.1.102"),
IPAddress.Parse("127.0.1.103"),
IPAddress.Parse("127.0.1.104"),
IPAddress.Parse("127.0.1.105"),
IPAddress.Parse("127.0.1.106"),
};
}
/// <summary>
/// 反垃圾訊息服務
/// </summary>
public class AntiSpamService
{
private readonly DomainSpamhausService _dnsblService = new();
private static readonly Regex s_urlPattern = new(
@"(https?:\/\/)?(?<LINK>[\-a-z0-9@:%\/\._+~#=]+)",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
/// <summary>
/// 判斷文字內容是否為垃圾訊息。
/// </summary>
/// <param name="rawContent"></param>
/// <returns></returns>
public async Task<bool> IsSpam(string rawContent)
{
var m = s_urlPattern.Match(rawContent);
// 不包含連結直接當作有效內容
if (!m.Success)
return false;
// 取得連結
var roughUri = m.Groups["LINK"].Value;
// 從連結中取得 FQDN
var uriBuilder = new UriBuilder(roughUri);
var fqdn = uriBuilder.Host;
// 驗證連結是否存在於 DNSBL
return await _dnsblService
.IsBlacklisted(fqdn)
.ConfigureAwait(false);
}
}
}
@Orlys
Copy link
Author

Orlys commented Oct 3, 2022

使用範例

var content = """
    這是一封詐騙訊息,內含可以賺錢的連結。https://go.diryjyaz.com/30678887
    """
    ;

var antiSpamService = new AntiSpamService();
var isSpam = await antiSpamService.IsSpam(content);
Console.WriteLine(content);
Console.WriteLine("is spam? " + (isSpam ? "yes" : "no"));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment