你是否观察到过这种现象,在访问Github时,有的时候能正常访问,有的时候再次刷新就访问不了,那么能不能有什么办法能一直访问。答案是有,就是在DNS层面能保证一直稳定获取可用并且快速的IP,这就是FastGithub的原理,笔者结合Github上的开源Code来讲下DNS的一些细节。
FastGithub - DnsServer
当然,也许FastGithub的原理有很多种,这只是其中一种。
首先,构造一个DnsServer,
1 2
| var dnsServer = new DnsServer(githubRequestResolver, "114.114.114.114"); dnsServer.Listen();
|
DnsServer的构造函数,第一个参数request resolver可以自定义自己的dns resolve方式,第二个参数定义了上游的DnsServer, 114.114.114.114是国内公共的Dns服务器地址,也可以选择其他的公共Dns服务器。
拓展阅读,有没有好奇过Dns是如何查询的,用的什么协议:
总结来说:
UDP协议,53号端口:用于大部分的普通DNS查询。
TCP协议,53号端口:用于数据量较大的DNS查询或需要可靠性传输的情况。
FastGithub - Dns
我们看下GithubRequestResolver:
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
| public class GithubRequestResolver : IRequestResolver { public Task<IResponse> Resolve(IRequest request, CancellationToken cancellationToken = default) { var response = Response.FromRequest(request); var question = request.Questions.FirstOrDefault();
if (question != null && question.Type == RecordType.A) { var domain = question.Name.ToString(); var fastAddress = domain.Contains("github", StringComparison.OrdinalIgnoreCase) ? this.results.FindFastAddress(domain) : default;
if (fastAddress != null) { var record = new IPAddressResourceRecord(question.Name, fastAddress); response.AnswerRecords.Add(record); this.logger.LogInformation(record.ToString()); } }
return Task.FromResult<IResponse>(response); } }
|
这段代码自定义了Dns的Resolve方式,当目前domain为github时,从库中找寻最开的IP地址,然后构造Dns Response返回,这就是这种FastGithub的核心。这个只是简单的示例代码,寻找最快的IP可以是先准备一批IP,然后查询哪个最快返回,也可以是先Lookup查找结果。
注意代码中需要判断Dns RecordType.A,只有A记录才需要重写Record,那么Dns都有什么类型,为什么只有A类型需要特殊处理?
Dns的类型
1 2 3 4 5 6 7 8 9 10 11
| > nslookup -query=TXT baidu.com > baidu.com text = "_globalsign-domain-verification=qjb28W2jJSrWj04NHpB0CvgK9tle5JkOq-EcyWBgnE" baidu.com text = "google-site-verification=GHb98-6msqyx_qqjGl5eRatD3QTHyVB6-xQ3gJB5UwM" baidu.com text =
"9279nznttl321bxp1j464rd9vpps246v" baidu.com text =
"v=spf1 include:spf1.baidu.com include:spf2.baidu.com include:spf3.baidu.com include:spf4.baidu.com mx ptr -all"
|
1 2
| > nslookup -query=MX microsoft.com > microsoft.com MX preference = 10, mail exchanger = microsoft-com.mail.protection.outlook.com
|
上述例子说明microsoft.com对应的邮件服务器为outlook.com, 而这种记录有一个很典型的应用,可以判断一个microsoft 365 tenant是否属于gcc high。大家知道微软的microsoft 365有多种类型,常用的有commercial, usgov以及21v, 而对应的mail server分别是outlook.com和outlook.us, 那么通过MX记录就可以很快的判断出来是属于哪种类型。对应的c#代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| var lookup = new LookupClient(); var result = await lookup.QueryAsync(domain, QueryType.MX).ConfigureAwait(false); foreach (var item in result.Answers) { var mxRecord = item as MxRecord; if (mxRecord != null) { var exchange = mxRecord.Exchange; if (exchange.ToString().EndsWith("com")) { return AzureEnvironment.Worldwide; } else if (exchange.ToString().EndsWith("us")) { return AzureEnvironment.USGovGCCHigh; } else if (exchange.ToString().EndsWith("cn")) { return AzureEnvironment.China; } } }
|