Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using System.Globalization;
using System.Windows.Data;
using NETworkManager.Localization.Resources;
using NETworkManager.Models.RDAP;

namespace NETworkManager.Converters;

/// <summary>
/// Convert <see cref="RDAPQueryType" /> to an example input (watermark).
/// </summary>
public sealed class RDAPQueryTypeToWatermarkConverter : IValueConverter
{
/// <summary>
/// Convert <see cref="RDAPQueryType" /> to an example input (watermark).
/// </summary>
/// <param name="value">Object from type <see cref="RDAPQueryType" />.</param>
/// <param name="targetType"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns>Example input for the <see cref="RDAPQueryType" />.</returns>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value switch
{
RDAPQueryType.Nameserver => StaticStrings.ExampleRDAPNameserver,
RDAPQueryType.TLD => StaticStrings.ExampleTLD,
RDAPQueryType.IPAddress => StaticStrings.ExampleIPAddressOrCIDR,
RDAPQueryType.ASN => StaticStrings.ExampleASN,
RDAPQueryType.Entity => StaticStrings.ExampleRDAPEntityHandle,
_ => StaticStrings.ExampleDomain
};
}

/// <summary>
/// !!! Method not implemented !!!
/// </summary>
/// <param name="value"></param>
/// <param name="targetType"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns></returns>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -372,4 +372,7 @@
<data name="ExampleRDAPEntityHandle" xml:space="preserve">
<value>ORG-RIEN1-RIPE</value>
</data>
<data name="ExampleRDAPNameserver" xml:space="preserve">
<value>a.iana-servers.net</value>
</data>
</root>
72 changes: 72 additions & 0 deletions Source/NETworkManager.Localization/Resources/Strings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions Source/NETworkManager.Localization/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -4809,4 +4809,28 @@ Cloudflare may log your IP address and network information. See Cloudflare's pri
<data name="DeleteRulesX" xml:space="preserve">
<value>Delete rules ({0})</value>
</data>
<data name="RDAPQueryType_Auto" xml:space="preserve">
<value>Auto</value>
</data>
<data name="EnterValidRDAPQuery" xml:space="preserve">
<value>Enter a valid domain, IP address, AS number or entity handle!</value>
</data>
<data name="RDAPTimeoutAfterXSeconds" xml:space="preserve">
<value>The RDAP server did not respond within {0} seconds.</value>
</data>
<data name="RDAPQueryType_Nameserver" xml:space="preserve">
<value>Nameserver</value>
</data>
<data name="EnterValidNameserver" xml:space="preserve">
<value>Enter a valid nameserver (e.g., "ns1.example.com")!</value>
</data>
<data name="ASNumbers" xml:space="preserve">
<value>AS numbers</value>
</data>
<data name="RDAPDots" xml:space="preserve">
<value>RDAP...</value>
</data>
<data name="RDAPNoRecordForXShowingY" xml:space="preserve">
<value>No RDAP record found for "{0}", showing the registration data of "{1}".</value>
</data>
</root>
29 changes: 23 additions & 6 deletions Source/NETworkManager.Models/RDAP/RDAPBootstrapService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ public List<string> GetBaseUrls(RDAPQuery query)
var urls = query.Type switch
{
RDAPQueryType.TLD => [IANARootZoneUrl],
RDAPQueryType.Domain => FindDomain(query.DomainName),
// A nameserver is served by the registry of its TLD (RFC 9224 4).
RDAPQueryType.Domain or RDAPQueryType.Nameserver => FindDomain(query.DomainName),
RDAPQueryType.IPAddress => FindIPAddress(query.IPAddress, query.PrefixLength),
RDAPQueryType.ASN => FindASN(query.ASN),
RDAPQueryType.Entity => FindEntity(query.Handle),
Expand Down Expand Up @@ -319,14 +320,22 @@ private async Task UpdateAsync(string cacheDirectory, bool force, CancellationTo

Directory.CreateDirectory(_cacheDirectory);

// Load the cached files first, so a file that can't be parsed is downloaded again in this update (see
// ReadServices).
if (_dns == null)
LoadRegistries();

var attempted = false;
var contentChanged = false;
Exception networkError = null;

foreach (var info in _cacheInfos)
{
// "Expires" is the time of the next check, after a successful update as well as after a failure.
if (!force && info.Expires > DateTime.Now)
var path = Path.Combine(_cacheDirectory, info.FileName);

// "Expires" is the time of the next check, after a successful update as well as after a failure. A
// missing file is tried with every query, since the query type can't be used without it.
if (!force && info.Expires > DateTime.Now && File.Exists(path))
continue;

attempted = true;
Expand All @@ -340,8 +349,6 @@ private async Task UpdateAsync(string cacheDirectory, bool force, CancellationTo
continue;
}

var path = Path.Combine(_cacheDirectory, info.FileName);

try
{
contentChanged |= await DownloadAsync(info, path, File.Exists(path), cancellationToken)
Expand Down Expand Up @@ -382,7 +389,7 @@ private async Task UpdateAsync(string cacheDirectory, bool force, CancellationTo
/// <summary>
/// Records a failed update. A cached file is retried after <see cref="RetryInterval" />, at most
/// <see cref="MaxFailedAttempts" /> times, then after the regular <see cref="RefreshInterval" />. A missing file
/// is retried after <see cref="RetryInterval" />, since the query type cannot be used without it.
/// is tried again with the next query (see <see cref="UpdateAsync" />).
/// </summary>
private void RecordFailure(RDAPBootstrapCacheInfo info, Exception ex)
{
Expand Down Expand Up @@ -680,6 +687,16 @@ private void LoadRegistries()
catch (Exception ex)
{
Log.Error($"Could not parse RDAP bootstrap file {path}.", ex);

// Download the file again with the next query. Without ETag and Last-Modified, the request is not
// conditional, so the server can't answer with "304 Not Modified" and the file is replaced.
var info = _cacheInfos.First(x => x.Type == type);

info.ETag = null;
info.LastModified = null;
info.Expires = null;
info.LastError = ex.Message;

return null;
}
}
Expand Down
Loading
Loading