public async Task <bool> UpdateIpAddressForSubdomain(string hostedZoneId, string fqdn, string newIpAddress) { using (AmazonRoute53Client route53Client = GetAmazonRoute53Client()) { ListResourceRecordSetsResponse records = await route53Client.ListResourceRecordSetsAsync(new ListResourceRecordSetsRequest(hostedZoneId)); // Look for an A record matching the FQDN that was passed in ResourceRecordSet matchingRecordSet = records?.ResourceRecordSets.FirstOrDefault(prop => prop.Name == fqdn && prop.Type == RRType.A); if (matchingRecordSet != null && matchingRecordSet.ResourceRecords.Any()) { if (matchingRecordSet.ResourceRecords.First().Value != newIpAddress) { matchingRecordSet.ResourceRecords.First().Value = newIpAddress; ChangeBatch change = new ChangeBatch(); change.Changes.Add(new Change(ChangeAction.UPSERT, matchingRecordSet)); ChangeResourceRecordSetsResponse changeRequest = await route53Client.ChangeResourceRecordSetsAsync(new ChangeResourceRecordSetsRequest(hostedZoneId, change)); Log.Information("[Runtime = {StartTime}] Change request submitted to change subdomain {Subdomain} IP address to {IPAddress}.", Settings.StartTime, fqdn, newIpAddress); return(changeRequest.HttpStatusCode == System.Net.HttpStatusCode.OK); } else { Log.Information("[Runtime = {StartTime}] Subdomain {Subdomain} found, but the IP address was already {IPAddress}.", Settings.StartTime, fqdn, newIpAddress); } } return(false); } }
public async Task DeleteTxtRecordAsync(DnsZone zone, string relativeRecordName) { var recordName = $"{relativeRecordName}.{zone.Name}."; var listRequest = new ListResourceRecordSetsRequest(zone.Id) { StartRecordName = recordName, StartRecordType = RRType.TXT }; var listResponse = await _amazonRoute53Client.ListResourceRecordSetsAsync(listRequest); if (listResponse.ResourceRecordSets.Count == 0) { return; } var changes = listResponse.ResourceRecordSets .Select(x => new Change { Action = ChangeAction.DELETE, ResourceRecordSet = x }) .ToList(); var request = new ChangeResourceRecordSetsRequest(zone.Id, new ChangeBatch(changes)); await _amazonRoute53Client.ChangeResourceRecordSetsAsync(request); }
/// <summary> /// To retrieve a list of record sets for a particular hosted zone. /// </summary> /// <param name="hostedZoneId">The ID of the hosted zone whos record sets you want to list</param> /// <param name="settings">The <see cref="Route53Settings"/> required to connect to Route53.</param> /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param> public async Task <IList <ResourceRecordSet> > GetResourceRecordSets(string hostedZoneId, Route53Settings settings, CancellationToken cancellationToken = default(CancellationToken)) { if (String.IsNullOrEmpty(hostedZoneId)) { throw new ArgumentNullException("hostedZoneId"); } ListResourceRecordSetsRequest request = new ListResourceRecordSetsRequest(hostedZoneId); AmazonRoute53Client client = this.GetClient(settings); ListResourceRecordSetsResponse response = await client.ListResourceRecordSetsAsync(request); if (response.HttpStatusCode == HttpStatusCode.OK) { _Log.Verbose("Listing record sets"); return(response.ResourceRecordSets); } else { _Log.Error("Could not list record sets"); return(null); } }
public static void ListHostNames() { if (!quiet) { Console.WriteLine($"Domain = {domain}"); } string zoneId = FindHostedZoneID(domain); if (zoneId == null) { throw new Exception("Zone not found"); } bool more = true; bool first = true; string start = ""; while (more) { ListResourceRecordSetsRequest r = new ListResourceRecordSetsRequest(zoneId); r.MaxItems = "150"; if (!first) { r.StartRecordName = start; } first = false; ListResourceRecordSetsResponse res = c.ListResourceRecordSetsAsync(r).Result; foreach (var s in res.ResourceRecordSets) { string firstVal = (s.ResourceRecords != null && s.ResourceRecords.Count > 0) ? s.ResourceRecords[0].Value : ""; Console.WriteLine($"{s.Name.PadRight(60)}" + (quiet ? "" : $"\t{s.Type}\t{firstVal}")); /* * if (!quiet) * { * foreach(var rr in s.ResourceRecords) * { * Console.WriteLine($"\t{rr.Value}"); * } * } */ } more = res.IsTruncated; if (more) { start = res.NextRecordName; } } }
private static async Task <ResourceRecordSet> GetResourceRecordSet(string hostedZoneID, string domainName) { try { var listResourceRecordSetsRequest = new ListResourceRecordSetsRequest(hostedZoneID); var listResourceRecordSetsResponse = await client.ListResourceRecordSetsAsync(listResourceRecordSetsRequest); return(listResourceRecordSetsResponse.ResourceRecordSets.SingleOrDefault(x => x.Name == domainName && x.Type == RRType.A)); } catch (Exception exception) { logger.Error(exception, ""); throw; } }
/// <summary> /// /// </summary> /// <param name="hostzoneId">Sample: /hostedzone/ZW9CIJG5IAQYD</param> /// <param name="resourceRecordSetName">Sample api.infra.safearrival.testschoolmessenger.com.</param> /// <returns>Example: infra-Admin-ALB-747523918.us-east-2.elb.amazonaws.com (Regular)Or /// admin.infra.safearrival.testschoolmessenger.com.s3-website.us-east-2.amazonaws.com (Maintenance)</returns> public async Task <List <string> > GetRecorSetValues(string hostzoneId, List <string> resourceRecordSetNames) { var ret = new List <string>(); var request = new ListResourceRecordSetsRequest() { HostedZoneId = hostzoneId, //StartRecordName = resourceRecordSetName }; var response = await client.ListResourceRecordSetsAsync(request); foreach (var name in resourceRecordSetNames) { var recordSet = response.ResourceRecordSets.Find(o => o.Name == name); if (recordSet != null && recordSet.ResourceRecords.Count > 0) { ret.Add(recordSet.ResourceRecords[0].Value); } } return(ret); }
private async static Task <bool> UpdateIpAddressForSubdomain(string hostedZoneId, string fqdn, string newIpAddress) { AmazonRoute53Config config = new AmazonRoute53Config() { RegionEndpoint = RegionEndpoint.GetBySystemName(Settings.AWSRegion) // TODO: inject }; using (AmazonRoute53Client route53Client = new AmazonRoute53Client(Settings.AWSAccessKeyId, Settings.AWSAccessKeySecret, config)) { ListResourceRecordSetsResponse records = await route53Client.ListResourceRecordSetsAsync(new ListResourceRecordSetsRequest(hostedZoneId)); ResourceRecordSet matchingRecordSet = records?.ResourceRecordSets.FirstOrDefault(prop => prop.Name == fqdn && prop.Type == RRType.A); if (matchingRecordSet != null && matchingRecordSet.ResourceRecords.FirstOrDefault() != null) { if (matchingRecordSet.ResourceRecords.FirstOrDefault().Value != newIpAddress) { matchingRecordSet.ResourceRecords.FirstOrDefault().Value = newIpAddress; ChangeBatch change = new ChangeBatch(); change.Changes.Add(new Change(ChangeAction.UPSERT, matchingRecordSet)); ChangeResourceRecordSetsResponse changeRequest = await route53Client.ChangeResourceRecordSetsAsync(new ChangeResourceRecordSetsRequest(hostedZoneId, change)); Log.Information("[Runtime = {StartTime}] Change request submitted to change subdomain {Subdomain} IP address to {IPAddress}.", startTime, fqdn, newIpAddress); return(changeRequest.HttpStatusCode == System.Net.HttpStatusCode.OK); } else { Log.Information("[Runtime = {StartTime}] Subdomain {Subdomain} found, but the IP address was already {IPAddress}.", startTime, fqdn, newIpAddress); } } else { // New subdomain Log.Information("[Runtime = {StartTime}] Subdomain {Subdomain} record not found.", startTime, fqdn); } return(false); } }
public async Task <ActionResult> CreateRecord(DnsRecord request) { // https://docs.aws.amazon.com/sdk-for-net/v2/developer-guide/route53-apis-intro.html // find zone var zone = await ResolveMatchingZone(request); if (zone != null) { // get existing record set for current TXT records with this name var response = await _route53Client.ListResourceRecordSetsAsync( new ListResourceRecordSetsRequest { StartRecordName = request.RecordName, StartRecordType = "TXT", MaxItems = "1", HostedZoneId = zone.Id } ); var targetRecordSet = response.ResourceRecordSets.FirstOrDefault(r => (r.Name == request.RecordName || r.Name == request.RecordName + ".") && r.Type.Value == "TXT"); if (targetRecordSet != null) { targetRecordSet.ResourceRecords.Add( new ResourceRecord { Value = "\"" + request.RecordValue + "\"" } ); } else { targetRecordSet = new ResourceRecordSet() { Name = request.RecordName, TTL = 5, Type = RRType.TXT, ResourceRecords = new List <ResourceRecord> { new ResourceRecord { Value = "\"" + request.RecordValue + "\"" } } }; } try { // requests for *.domain.com + domain.com use the same TXT record name, so we // need to allow multiple entires rather than doing Upsert var result = await ApplyDnsChange(zone, targetRecordSet, ChangeAction.UPSERT); return(new ActionResult { IsSuccess = true, Message = $"Dns Record Created/Updated: {request.RecordName}" }); } catch (AmazonRoute53Exception exp) { return(new ActionResult { IsSuccess = false, Message = $"Dns Record Create/Update: {request.RecordName} - {exp.Message}" }); } } else { return(new ActionResult { IsSuccess = false, Message = "DNS Zone match could not be determined." }); } }
public List <MultiClientEntry> GetClients() { //Output Output($"MCS: Starting Get Clients"); //1) Get the current data-text from R53 //New the Route 53 Client AmazonRoute53Client r53Client = new AmazonRoute53Client( Config.BaseSettings.AWSAccessKeyID, Config.BaseSettings.AWSSecretAccessKey, new AmazonRoute53Config { RegionEndpoint = RegionEndpoint }); //Define the request ListResourceRecordSetsRequest listResourceRecordSetsRequest = new ListResourceRecordSetsRequest { HostedZoneId = Config.MultiClientSettings.Route53.R53ZoneId, MaxItems = 1.ToString(), StartRecordName = Config.MultiClientSettings.Route53.Name }; //Get the response ListResourceRecordSetsResponse listResourceRecordSetsResponse = r53Client .ListResourceRecordSetsAsync(listResourceRecordSetsRequest) .GetAwaiter() .GetResult(); //Get the Data Text (if any) //listResourceRecordSetsResponse.ResourceRecordSets[0].ResourceRecords[0].Value string dataText = listResourceRecordSetsResponse .ResourceRecordSets? .Where(rrsi => string.Equals(rrsi.Name, Config.MultiClientSettings.Route53.Name, StringComparison.InvariantCultureIgnoreCase)) .FirstOrDefault()? .ResourceRecords? .FirstOrDefault()? .Value? .Trim('"'); if (string.IsNullOrWhiteSpace(dataText) || string.IsNullOrWhiteSpace(dataText.Trim('"'))) { //Since there somehow were no existing data in R53 //We just return an empty list //Output Output($"MCS: Found no existing record"); //return return(new List <MultiClientEntry>()); } //2) Decode the data string to a JSON string (decompress, decrypt) //Decrypt and Decompress dataText = dataText.DecryptThenDecompress(Config.MultiClientSettings.Route53.EncryptionPassword); //3) Turn the Data Text into List //De-serialize the JSON to the return value List <MultiClientEntry> multiClientEntries = JsonConvert.DeserializeObject <List <MultiClientEntry> >(dataText); //Output Output($"MCS: Completed Get Clients. Got {multiClientEntries.Count}"); //return return(multiClientEntries); }
/// <summary> /// This method does all of the work to update the DNS records with our current WAN IP. This is separated from the main /// method to make it easier in the future to perform batch updates (if needed). /// </summary> /// <param name="id">The AWS Access key ID</param> /// <param name="secret">The AWS Access key secret</param> /// <param name="domain">The domain name we are going to be updating records for (e.g. shawnlehner.com)</param> /// <param name="subdomain">The subdomain we would like to update (e.g. "house" if we were updating house.shawnlehner.com)</param> private static async Task PerformDnsUpdate(string id, string secret, string domain, string subdomain) { #region Lookup Current WAN IP // We use ipify.org to quickly/easily get our external WAN IP address which we can later use // for updating our DNS records. string ip = null; HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://api.ipify.org"); using (Stream s = (await request.GetResponseAsync()).GetResponseStream()) using (StreamReader r = new StreamReader(s)) { ip = r.ReadToEnd(); } #endregion // Combine our domain and subdomain to get the full record name string recordName = subdomain.Trim('.') + "." + domain.Trim('.'); // Create our AWS API client for sending requests to the Route53 API AmazonRoute53Client client = new AmazonRoute53Client(id, secret, RegionEndpoint.USEast1); #region Lookup current state of the domain on Route53 // Lookup the zone for our domain HostedZone zone = (await client.ListHostedZonesByNameAsync(new ListHostedZonesByNameRequest { DNSName = domain })).HostedZones.First(); // Lookup our current records to see if we need to make an update ListResourceRecordSetsResponse recordSet = await client.ListResourceRecordSetsAsync(new ListResourceRecordSetsRequest { HostedZoneId = zone.Id, MaxItems = "1", StartRecordName = recordName }); #endregion // Check to see if our IP is already up to date. No sense making a change if we don't need to. if (recordSet.ResourceRecordSets.Count > 0 && recordSet.ResourceRecordSets[0].Name.Trim('.') == recordName && recordSet.ResourceRecordSets[0].ResourceRecords[0].Value == ip) { return; } #region Request DNS record update with new IP // Our IP address is not up-to-date so we need to make a change request. We use UPSERT action which // will work whether or not a record already exists. ChangeResourceRecordSetsRequest changeRequest = new ChangeResourceRecordSetsRequest { HostedZoneId = zone.Id, ChangeBatch = new ChangeBatch { Changes = new List <Change> { new Change { ResourceRecordSet = new ResourceRecordSet { Name = recordName, TTL = 60, Type = RRType.A, ResourceRecords = new List <ResourceRecord> { new ResourceRecord { Value = ip } } }, Action = ChangeAction.UPSERT } } } }; // Send our change request to the API ChangeResourceRecordSetsResponse response = await client.ChangeResourceRecordSetsAsync(changeRequest); // Check our response code to verify everything worked if (response.HttpStatusCode != HttpStatusCode.OK) { throw new Exception("API request to update DNS record has failed."); } #endregion }