22using System . Net ;
33using NetTools ;
44using System ;
5+ using DnsClient ;
56
67namespace FWO . Basics
78{
89 public static class IpOperations
910 {
11+
12+ // reuse the client to avoid socket churn; disable client-side cache
13+ private static readonly LookupClient ReverseLookupClient = new ( new LookupClientOptions
14+ {
15+ UseCache = false ,
16+ ContinueOnDnsError = true ,
17+ ThrowDnsErrors = false
18+ } ) ;
19+
20+ public static async Task < IReadOnlyList < string > > DnsReverseLookUpAllAsync (
21+ IPAddress address ,
22+ CancellationToken cancellationToken = default )
23+ {
24+ // QueryReverseAsync issues a PTR query and returns all answers from the DNS server
25+ IDnsQueryResponse response = await ReverseLookupClient . QueryReverseAsync ( address , cancellationToken )
26+ . ConfigureAwait ( false ) ;
27+
28+ if ( response . HasError || response . Answers . Count == 0 )
29+ {
30+ return Array . Empty < string > ( ) ;
31+ }
32+
33+ return response . Answers
34+ . PtrRecords ( )
35+ . Select ( ptr => ptr . PtrDomainName . Value . TrimEnd ( '.' ) ) // drop trailing dot
36+ . Distinct ( StringComparer . OrdinalIgnoreCase )
37+ . ToArray ( ) ;
38+ }
39+
40+ public static async Task < string > DnsReverseLookUpPreferredAsync ( IPAddress address )
41+ {
42+ IReadOnlyList < string > names = await DnsReverseLookUpAllAsync ( address ) ;
43+ return names . FirstOrDefault ( name => ! name . StartsWith ( "lx" , StringComparison . OrdinalIgnoreCase ) )
44+ ?? names . FirstOrDefault ( )
45+ ?? string . Empty ;
46+ }
47+
1048 public static async Task < string > DnsReverseLookUp ( IPAddress address )
1149 {
1250 try
1351 {
1452 return ( await Dns . GetHostEntryAsync ( address ) ) . HostName ;
1553 }
16- catch ( Exception )
54+ catch ( Exception )
1755 {
1856 return "" ;
1957 }
@@ -51,25 +89,25 @@ public static bool TryParseIPStringToRange(this string ipString, out (string Sta
5189 bool ipStartOK = IPAddress . TryParse ( ipStart , out IPAddress ? ipAdressStart ) ;
5290 bool ipEndOK = IPAddress . TryParse ( ipEnd , out IPAddress ? ipAdressEnd ) ;
5391
54- if ( ipAdressStart is null || ipAdressEnd is null )
92+ if ( ipAdressStart is null || ipAdressEnd is null )
5593 {
5694 return false ;
5795 }
5896
59- if ( strictv4Parse && ipAdressStart ? . AddressFamily == AddressFamily . InterNetwork && ipAdressEnd ? . AddressFamily == AddressFamily . InterNetwork )
97+ if ( strictv4Parse && ipAdressStart ? . AddressFamily == AddressFamily . InterNetwork && ipAdressEnd ? . AddressFamily == AddressFamily . InterNetwork )
6098 {
61- if ( ! IsValidIPv4 ( ipStart ) || ! IsValidIPv4 ( ipEnd ) )
99+ if ( ! IsValidIPv4 ( ipStart ) || ! IsValidIPv4 ( ipEnd ) )
62100 {
63101 return false ;
64102 }
65103 }
66104
67- if ( ! ipStartOK || ! ipEndOK )
105+ if ( ! ipStartOK || ! ipEndOK )
68106 {
69107 return false ;
70108 }
71109
72- if ( ! IPAddress . TryParse ( ipStart , out _ ) || ! IPAddress . TryParse ( ipEnd , out _ ) )
110+ if ( ! IPAddress . TryParse ( ipStart , out _ ) || ! IPAddress . TryParse ( ipEnd , out _ ) )
73111 {
74112 return false ;
75113 }
@@ -79,51 +117,52 @@ public static bool TryParseIPStringToRange(this string ipString, out (string Sta
79117
80118 return true ;
81119 }
82- catch ( Exception )
120+ catch ( Exception )
83121 {
84122 return false ;
85123 }
86124 }
87125
88- public static bool TryParseIPString < T > ( this string ipString , out T ? ipResult , bool strictv4Parse = false )
126+ public static bool TryParseIPString < T > ( this string ipString , out T ? ipResult , bool strictv4Parse = false )
89127 {
90128 ipResult = default ;
91-
129+
92130 try
93131 {
94132 ( string ipStart , string ipEnd ) = SplitIpToRange ( ipString ) ;
95133
96134 bool ipStartOK = IPAddress . TryParse ( ipStart , out IPAddress ? ipAdressStart ) ;
97135 bool ipEndOK = IPAddress . TryParse ( ipEnd , out IPAddress ? ipAdressEnd ) ;
98136
99- if ( ipAdressStart is null || ipAdressEnd is null )
137+ if ( ipAdressStart is null || ipAdressEnd is null )
100138 {
101139 return false ;
102140 }
103141
104- if ( strictv4Parse && ipAdressStart ? . AddressFamily == AddressFamily . InterNetwork && ipAdressEnd ? . AddressFamily == AddressFamily . InterNetwork )
142+ if ( strictv4Parse && ipAdressStart ? . AddressFamily == AddressFamily . InterNetwork && ipAdressEnd ? . AddressFamily == AddressFamily . InterNetwork )
105143 {
106- if ( ! IsValidIPv4 ( ipStart ) || ! IsValidIPv4 ( ipEnd ) )
144+ if ( ! IsValidIPv4 ( ipStart ) || ! IsValidIPv4 ( ipEnd ) )
107145 {
108146 return false ;
109147 }
110148 }
111149
112- if ( ! ipStartOK || ! ipEndOK )
150+ if ( ! ipStartOK || ! ipEndOK )
113151 {
114152 return false ;
115153 }
116154
117- if ( typeof ( T ) == typeof ( ( string , string ) ) )
155+ if ( typeof ( T ) == typeof ( ( string , string ) ) )
118156 {
119157 ipResult = ( T ) Convert . ChangeType ( ( ipAdressStart ! . ToString ( ) , ipAdressEnd ! . ToString ( ) ) , typeof ( T ) ) ;
120158 return true ;
121159 }
122- else if ( typeof ( T ) == typeof ( IPAddressRange ) && IPAddressRange . TryParse ( ipString , out IPAddressRange ipRange ) )
160+ else if ( typeof ( T ) == typeof ( IPAddressRange ) && IPAddressRange . TryParse ( ipString , out IPAddressRange ipRange ) )
123161 {
124162 ipResult = ( T ) Convert . ChangeType ( ipRange , typeof ( T ) ) ;
125163 return true ;
126- } else if ( typeof ( T ) == typeof ( ( IPAddress , IPAddress ) ) )
164+ }
165+ else if ( typeof ( T ) == typeof ( ( IPAddress , IPAddress ) ) )
127166 {
128167 Tuple < IPAddress , IPAddress > ? ipTuple = new ( ipAdressStart ! , ipAdressEnd ! ) ;
129168 ipResult = ( T ) Convert . ChangeType ( ipTuple , typeof ( T ) ) ;
@@ -132,7 +171,7 @@ public static bool TryParseIPString<T>(this string ipString, out T? ipResult, bo
132171
133172 return false ;
134173 }
135- catch ( Exception )
174+ catch ( Exception )
136175 {
137176 return false ;
138177 }
@@ -142,7 +181,7 @@ private static bool IsValidIPv4(string ipAddress)
142181 {
143182 byte [ ] addBytes = [ .. ipAddress . Split ( '.' ) . Where ( _ => byte . Parse ( _ ) <= 255 && byte . Parse ( _ ) >= 0 ) . Select ( byte . Parse ) ] ;
144183
145- return addBytes . Length == 4 ;
184+ return addBytes . Length == 4 ;
146185 }
147186
148187 public static string GetObjectType ( string ip1 , string ip2 )
@@ -333,11 +372,11 @@ public static int CompareIpValues(IPAddress ip1, IPAddress ip2)
333372 /// </summary>
334373 public static int CompareIpFamilies ( IPAddress ip1 , IPAddress ip2 )
335374 {
336- if ( ip1 . AddressFamily == AddressFamily . InterNetwork && ip2 . AddressFamily == AddressFamily . InterNetworkV6 )
375+ if ( ip1 . AddressFamily == AddressFamily . InterNetwork && ip2 . AddressFamily == AddressFamily . InterNetworkV6 )
337376 {
338377 return - 1 ;
339378 }
340- if ( ip1 . AddressFamily == AddressFamily . InterNetworkV6 && ip2 . AddressFamily == AddressFamily . InterNetwork )
379+ if ( ip1 . AddressFamily == AddressFamily . InterNetworkV6 && ip2 . AddressFamily == AddressFamily . InterNetwork )
341380 {
342381 return 1 ;
343382 }
0 commit comments