Skip to content

Commit b618b7f

Browse files
added infoblox
1 parent b28cc5b commit b618b7f

3 files changed

Lines changed: 138 additions & 0 deletions

File tree

AcmeCaPlugin/AcmeClientConfig.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,12 @@ public class AcmeClientConfig
3434
//IBM NS1 DNS Ns1_ApiKey
3535
public string Ns1_ApiKey { get; set; } = null;
3636

37+
// Infoblox DNS
38+
public string Infoblox_Host { get; set; } = null;
39+
public string Infoblox_Username { get; set; } = null;
40+
public string Infoblox_Password { get; set; } = null;
41+
public string Infoblox_WapiVersion { get; set; } = "2.12";
42+
public bool Infoblox_IgnoreSslErrors { get; set; } = false;
43+
3744
}
3845
}

AcmeCaPlugin/Clients/DNS/DnsProviderFactory.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ public static IDnsProvider Create(AcmeClientConfig config, ILogger logger)
3939
return new Ns1DnsProvider(
4040
config.Ns1_ApiKey
4141
);
42+
case "infoblox":
43+
return new InfobloxDnsProvider(
44+
config.Infoblox_Host,
45+
config.Infoblox_Username,
46+
config.Infoblox_Password,
47+
config.Infoblox_WapiVersion,
48+
config.Infoblox_IgnoreSslErrors
49+
);
4250
default:
4351
throw new NotSupportedException($"DNS provider '{config.DnsProvider}' is not supported.");
4452
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
using System;
2+
using System.Linq;
3+
using System.Net;
4+
using System.Net.Http;
5+
using System.Net.Http.Headers;
6+
using System.Net.Security;
7+
using System.Security.Cryptography.X509Certificates;
8+
using System.Text;
9+
using System.Text.Json;
10+
using System.Threading.Tasks;
11+
12+
public class InfobloxDnsProvider : IDnsProvider
13+
{
14+
private readonly string _host;
15+
private readonly string _username;
16+
private readonly string _password;
17+
private readonly string _wapiVersion;
18+
private readonly HttpClient _httpClient;
19+
private readonly JsonSerializerOptions _jsonOptions;
20+
21+
public InfobloxDnsProvider(string host, string username, string password, string wapiVersion = "2.12", bool ignoreSslErrors = false)
22+
{
23+
_host = host?.TrimEnd('/') ?? throw new ArgumentNullException(nameof(host));
24+
_username = username ?? throw new ArgumentNullException(nameof(username));
25+
_password = password ?? throw new ArgumentNullException(nameof(password));
26+
_wapiVersion = wapiVersion ?? "2.12";
27+
28+
var handler = new HttpClientHandler();
29+
if (ignoreSslErrors)
30+
{
31+
handler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;
32+
}
33+
34+
_httpClient = new HttpClient(handler)
35+
{
36+
BaseAddress = new Uri($"{_host}/wapi/v{_wapiVersion}/")
37+
};
38+
39+
var authValue = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{_username}:{_password}"));
40+
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authValue);
41+
42+
_jsonOptions = new JsonSerializerOptions
43+
{
44+
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
45+
};
46+
}
47+
48+
public async Task<bool> CreateRecordAsync(string recordName, string txtValue)
49+
{
50+
try
51+
{
52+
var payload = new
53+
{
54+
name = recordName.TrimEnd('.'),
55+
text = txtValue,
56+
ttl = 60,
57+
view = "default"
58+
};
59+
60+
var json = JsonSerializer.Serialize(payload);
61+
var content = new StringContent(json, Encoding.UTF8, "application/json");
62+
63+
var response = await _httpClient.PostAsync("record:txt", content);
64+
var result = await response.Content.ReadAsStringAsync();
65+
66+
Console.WriteLine($"[Infoblox] Create TXT: {response.StatusCode} - {result}");
67+
return response.IsSuccessStatusCode;
68+
}
69+
catch (Exception ex)
70+
{
71+
Console.WriteLine($"[Infoblox] Error creating TXT record: {ex.Message}");
72+
return false;
73+
}
74+
}
75+
76+
public async Task<bool> DeleteRecordAsync(string recordName)
77+
{
78+
try
79+
{
80+
var cleanName = recordName.TrimEnd('.');
81+
var searchUrl = $"record:txt?name={Uri.EscapeDataString(cleanName)}";
82+
83+
var searchResponse = await _httpClient.GetAsync(searchUrl);
84+
if (!searchResponse.IsSuccessStatusCode)
85+
{
86+
Console.WriteLine($"[Infoblox] Failed to search for record: {searchResponse.StatusCode}");
87+
return false;
88+
}
89+
90+
var searchJson = await searchResponse.Content.ReadAsStringAsync();
91+
var records = JsonDocument.Parse(searchJson).RootElement;
92+
93+
if (records.GetArrayLength() == 0)
94+
{
95+
Console.WriteLine($"[Infoblox] No TXT records found for {cleanName}");
96+
return false;
97+
}
98+
99+
var recordRef = records[0].GetProperty("_ref").GetString();
100+
if (string.IsNullOrEmpty(recordRef))
101+
{
102+
Console.WriteLine($"[Infoblox] Record reference is null or empty");
103+
return false;
104+
}
105+
106+
var deleteResponse = await _httpClient.DeleteAsync(recordRef);
107+
var result = await deleteResponse.Content.ReadAsStringAsync();
108+
109+
Console.WriteLine($"[Infoblox] Delete TXT: {deleteResponse.StatusCode} - {result}");
110+
return deleteResponse.IsSuccessStatusCode;
111+
}
112+
catch (Exception ex)
113+
{
114+
Console.WriteLine($"[Infoblox] Error deleting TXT record: {ex.Message}");
115+
return false;
116+
}
117+
}
118+
119+
public void Dispose()
120+
{
121+
_httpClient?.Dispose();
122+
}
123+
}

0 commit comments

Comments
 (0)