26
26
27
27
using System ;
28
28
using System . IO ;
29
+ using System . Net ;
30
+ using System . Linq ;
29
31
using System . Text ;
30
32
using System . Threading ;
31
33
using System . Threading . Tasks ;
32
34
using System . Collections . Generic ;
33
35
34
- using Heijden . DNS ;
36
+ using DnsClient ;
35
37
36
38
using Org . BouncyCastle . Crypto ;
37
39
@@ -42,49 +44,57 @@ namespace DkimVerifierExample
42
44
{
43
45
class DkimPublicKeyLocator : DkimPublicKeyLocatorBase
44
46
{
47
+ static readonly char [ ] ColonDelimeter = new char [ ] { ':' } ;
45
48
readonly Dictionary < string , AsymmetricKeyParameter > cache ;
46
- readonly Resolver resolver ;
49
+ readonly LookupClient dnsClient ;
47
50
48
51
public DkimPublicKeyLocator ( )
49
52
{
50
53
cache = new Dictionary < string , AsymmetricKeyParameter > ( ) ;
51
54
52
- resolver = new Resolver ( "8.8.8.8" ) {
53
- TransportType = TransportType . Udp ,
55
+ var options = new LookupClientOptions ( IPAddress . Parse ( "8.8.8.8" ) ) {
54
56
UseCache = true ,
55
57
Retries = 3
56
58
} ;
59
+
60
+ dnsClient = new LookupClient ( options ) ;
57
61
}
58
62
59
- AsymmetricKeyParameter DnsLookup ( string domain , string selector , CancellationToken cancellationToken )
63
+ AsymmetricKeyParameter GetPublicKey ( string query , IDnsQueryResponse response )
60
64
{
61
- var query = selector + "._domainkey." + domain ;
62
-
63
- // checked if we've already fetched this key
64
- if ( cache . TryGetValue ( query , out var pubkey ) )
65
- return pubkey ;
66
-
67
- // make a DNS query
68
- var response = resolver . Query ( query , QType . TXT ) ;
69
65
var builder = new StringBuilder ( ) ;
70
66
71
67
// combine the TXT records into 1 string buffer
72
- foreach ( var record in response . RecordsTXT ) {
73
- foreach ( var text in record . TXT )
68
+ foreach ( var record in response . Answers . TxtRecords ( ) ) {
69
+ foreach ( var text in record . Text )
74
70
builder . Append ( text ) ;
75
71
}
76
72
77
73
var txt = builder . ToString ( ) ;
78
74
79
- pubkey = GetPublicKey ( txt ) ;
75
+ var pubkey = GetPublicKey ( txt ) ;
80
76
cache . Add ( query , pubkey ) ;
81
77
82
78
return pubkey ;
83
79
}
84
80
81
+ AsymmetricKeyParameter DnsLookup ( string domain , string selector , CancellationToken cancellationToken )
82
+ {
83
+ var query = selector + "._domainkey." + domain ;
84
+
85
+ // checked if we've already fetched this key
86
+ if ( cache . TryGetValue ( query , out var pubkey ) )
87
+ return pubkey ;
88
+
89
+ // make a DNS query
90
+ var response = dnsClient . Query ( query , QueryType . TXT , QueryClass . IN ) ;
91
+
92
+ return GetPublicKey ( query , response ) ;
93
+ }
94
+
85
95
public override AsymmetricKeyParameter LocatePublicKey ( string methods , string domain , string selector , CancellationToken cancellationToken = default ( CancellationToken ) )
86
96
{
87
- var methodList = methods . Split ( new char [ ] { ':' } , StringSplitOptions . RemoveEmptyEntries ) ;
97
+ var methodList = methods . Split ( ColonDelimeter , StringSplitOptions . RemoveEmptyEntries ) ;
88
98
for ( int i = 0 ; i < methodList . Length ; i ++ ) {
89
99
if ( methodList [ i ] == "dns/txt" )
90
100
return DnsLookup ( domain , selector , cancellationToken ) ;
@@ -93,9 +103,29 @@ AsymmetricKeyParameter DnsLookup (string domain, string selector, CancellationTo
93
103
throw new NotSupportedException ( string . Format ( "{0} does not include any suported lookup methods." , methods ) ) ;
94
104
}
95
105
106
+ async Task < AsymmetricKeyParameter > DnsLookupAsync ( string domain , string selector , CancellationToken cancellationToken )
107
+ {
108
+ var query = selector + "._domainkey." + domain ;
109
+
110
+ // checked if we've already fetched this key
111
+ if ( cache . TryGetValue ( query , out var pubkey ) )
112
+ return pubkey ;
113
+
114
+ // make a DNS query
115
+ var response = await dnsClient . QueryAsync ( query , QueryType . TXT , QueryClass . IN , cancellationToken ) . ConfigureAwait ( false ) ;
116
+
117
+ return GetPublicKey ( query , response ) ;
118
+ }
119
+
96
120
public override Task < AsymmetricKeyParameter > LocatePublicKeyAsync ( string methods , string domain , string selector , CancellationToken cancellationToken = default ( CancellationToken ) )
97
121
{
98
- throw new NotImplementedException ( "Asynchronous DKIM public key lookup is not implemented in this sample." ) ;
122
+ var methodList = methods . Split ( ColonDelimeter , StringSplitOptions . RemoveEmptyEntries ) ;
123
+ for ( int i = 0 ; i < methodList . Length ; i ++ ) {
124
+ if ( methodList [ i ] == "dns/txt" )
125
+ return DnsLookupAsync ( domain , selector , cancellationToken ) ;
126
+ }
127
+
128
+ throw new NotSupportedException ( string . Format ( "{0} does not include any suported lookup methods." , methods ) ) ;
99
129
}
100
130
}
101
131
0 commit comments