public void OnTimer(object sender, System.Timers.ElapsedEventArgs args) { eventLog.WriteEntry(LogMessaging.SERVICE_MONITORING, EventLogEntryType.Information); string date = Utility.GetRoute53Date(); string authValue = Utility.GetAWSR53_SHA1AuthorizationValue(Keys.ACCESS_KEY_ID, Keys.SECRET_KEY, date); string externalIp = Utility.GetExternalIp(); ListHostedZonesResponse listHostedZonesResponse = API.GetListHostedZones(date, authValue); var hostedZone = listHostedZonesResponse.HostedZones.Where(x => x.Name == "pierrethelusma.com.").SingleOrDefault(); ListResourceRecordSetsResponse listResourceRecordSetsResponse = API.GetListResourceRecordSets(date, authValue, hostedZone.Id); var resourceRecordSet = listResourceRecordSetsResponse.ResourceRecordSets.Where(x => x.Name == "home.pierrethelusma.com." && x.Type == "A").SingleOrDefault(); ChangeResourceRecordSetsResponse changeResourceRecordSetsResponse = new ChangeResourceRecordSetsResponse(); if (resourceRecordSet == null) { eventLog.WriteEntry(LogMessaging.SERVICE_CREATING_DNS_ENTRY, EventLogEntryType.Information); changeResourceRecordSetsResponse = API.PostChangeResourceRecordSets(date, authValue, externalIp, hostedZone.Id, "home.pierrethelusma.com.", "A", "600", "CREATE"); } else { if (!resourceRecordSet.ResourceRecords.Any(x => x.Value == externalIp)) { eventLog.WriteEntry(LogMessaging.SERVICE_UPDATING_DNS_ENTRY, EventLogEntryType.Information); changeResourceRecordSetsResponse = API.PostChangeResourceRecordSets(date, authValue, externalIp, hostedZone.Id, "home.pierrethelusma.com.", "A", "600", "UPSERT"); } } }
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); } }
/// <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 IEnumerable <ResourceRecordSet> GetResourceRecordSets(HostedZone zone) { var request = new ListResourceRecordSetsRequest(zone.Id); ListResourceRecordSetsResponse response = _route53Client.ListResourceRecordSets(request); return(response.ResourceRecordSets); }
private static void UnmarshallResult(XmlUnmarshallerContext context, ListResourceRecordSetsResponse response) { int originalDepth = context.CurrentDepth; int targetDepth = originalDepth + 1; if (context.IsStartOfDocument) { targetDepth += 1; } while (context.Read()) { if (context.IsStartElement || context.IsAttribute) { if (context.TestExpression("ResourceRecordSets/ResourceRecordSet", targetDepth)) { var unmarshaller = ResourceRecordSetUnmarshaller.Instance; response.ResourceRecordSets.Add(unmarshaller.Unmarshall(context)); continue; } if (context.TestExpression("IsTruncated", targetDepth)) { var unmarshaller = BoolUnmarshaller.Instance; response.IsTruncated = unmarshaller.Unmarshall(context); continue; } if (context.TestExpression("NextRecordName", targetDepth)) { var unmarshaller = StringUnmarshaller.Instance; response.NextRecordName = unmarshaller.Unmarshall(context); continue; } if (context.TestExpression("NextRecordType", targetDepth)) { var unmarshaller = StringUnmarshaller.Instance; response.NextRecordType = unmarshaller.Unmarshall(context); continue; } if (context.TestExpression("NextRecordIdentifier", targetDepth)) { var unmarshaller = StringUnmarshaller.Instance; response.NextRecordIdentifier = unmarshaller.Unmarshall(context); continue; } if (context.TestExpression("MaxItems", targetDepth)) { var unmarshaller = StringUnmarshaller.Instance; response.MaxItems = unmarshaller.Unmarshall(context); continue; } } else if (context.IsEndElement && context.CurrentDepth < originalDepth) { return; } } return; }
/// <summary> /// Unmarshaller the response from the service to the response class. /// </summary> /// <param name="context"></param> /// <returns></returns> public override AmazonWebServiceResponse Unmarshall(XmlUnmarshallerContext context) { ListResourceRecordSetsResponse response = new ListResourceRecordSetsResponse(); UnmarshallResult(context, response); return(response); }
internal void UpdateInfo() { ListResourceRecordSetsResponse resp = myController.route53.ListResourceRecordSets(new ListResourceRecordSetsRequest() .WithHostedZoneId(this.ResponseData.Id)); //Check if there is a change bool Change = (currentRecordSet.Count != resp.ListResourceRecordSetsResult.ResourceRecordSets.Count); for (int i = 0; (!Change) && i < currentRecordSet.Count && i < resp.ListResourceRecordSetsResult.ResourceRecordSets.Count; i++) { Change = currentRecordSet[i].Name != resp.ListResourceRecordSetsResult.ResourceRecordSets[i].Name || currentRecordSet[i].SetIdentifier != resp.ListResourceRecordSetsResult.ResourceRecordSets[i].SetIdentifier || currentRecordSet[i].TTL != resp.ListResourceRecordSetsResult.ResourceRecordSets[i].TTL || currentRecordSet[i].Type != resp.ListResourceRecordSetsResult.ResourceRecordSets[i].Type || currentRecordSet[i].Weight != resp.ListResourceRecordSetsResult.ResourceRecordSets[i].Weight || currentRecordSet[i].ResourceRecords.Count != resp.ListResourceRecordSetsResult.ResourceRecordSets[i].ResourceRecords.Count ; if (resp.ListResourceRecordSetsResult.ResourceRecordSets[i].AliasTarget == null) { Change |= currentRecordSet[i].AliasTarget != null; } else { Change |= currentRecordSet[i].AliasTarget == null; Change |= currentRecordSet[i].AliasTarget.DNSName != resp.ListResourceRecordSetsResult.ResourceRecordSets[i].AliasTarget.DNSName; Change |= currentRecordSet[i].AliasTarget.HostedZoneId != resp.ListResourceRecordSetsResult.ResourceRecordSets[i].AliasTarget.HostedZoneId; } if (Change) { break; } foreach (var rr in currentRecordSet[i].ResourceRecords) { bool found = false; foreach (var r in resp.ListResourceRecordSetsResult.ResourceRecordSets[i].ResourceRecords) { if (rr.Value == r.Value) { found = true; break; } } Change |= !found; } } if (Change) { RecordsAvailable = true; currentRecordSet = resp.ListResourceRecordSetsResult.ResourceRecordSets; TriggerStatusChanged(); } }
private async Task <ListResourceRecordSetsResponse> getAwsResourceRecordsAsync(string hostedZoneId) { logger.LogInformation($"Getting List of Resource Records for hosted zone ID { hostedZoneId }..."); ListResourceRecordSetsRequest request = new ListResourceRecordSetsRequest { HostedZoneId = hostedZoneId }; ListResourceRecordSetsResponse records = await TheRoute53Client().ListResourceRecordSetsAsync(request); return(records); }
public override AmazonWebServiceResponse Unmarshall(XmlUnmarshallerContext context) { ListResourceRecordSetsResponse response = new ListResourceRecordSetsResponse(); while (context.Read()) { if (context.IsStartElement) { response.ListResourceRecordSetsResult = ListResourceRecordSetsResultUnmarshaller.GetInstance().Unmarshall(context); break; } } return(response); }
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 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 override Task <ListResourceRecordSetsResponse> ListResourceRecordSetsAsync(ListResourceRecordSetsRequest request, CancellationToken cancellationToken = default(CancellationToken)) { string ipAddress = string.Empty; if (request.HostedZoneId == TestConstants.FakeHostedZoneId) { if (request.StartRecordName == TestConstants.FakePublicDNSName) { ipAddress = TestConstants.FakePublicIpAddress; ListResourceRecordSetsPublicCalled = true; } else if (request.StartRecordName == TestConstants.FakePrivateDNSName) { ipAddress = TestConstants.FakePrivateIpAddress; ListResourceRecordSetsPrivateCalled = true; } TimesListResourceRecordSetsCalled++; } var fake = new ListResourceRecordSetsResponse { IsTruncated = false, ResourceRecordSets = new List <ResourceRecordSet> { new ResourceRecordSet { Type = RRType.A, Name = request.StartRecordName, ResourceRecords = new List <ResourceRecord> { new ResourceRecord { Value = ipAddress } } } } }; return(Task.Run(() => fake)); }
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 ListResourceRecordSetsResponse 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 }
public bool PrepareChallengeForValidation(string dnsKeyName, string dnsKeyValue) { try { route53Client = new AmazonRoute53Client(); HostedZone zone = null; if (zoneId != null) { GetHostedZoneResponse zoneResp = route53Client.GetHostedZone(new Amazon.Route53.Model.GetHostedZoneRequest { Id = zoneId }); zone = zoneResp.HostedZone; } else { ListHostedZonesResponse zones = route53Client.ListHostedZones(); string recordToZone = dnsKeyName; while (recordToZone.IndexOf('.') > 0) { recordToZone = recordToZone.Substring(recordToZone.IndexOf('.') + 1); zone = zones.HostedZones.Where(z => z.Name.Contains(recordToZone)).FirstOrDefault(); if (zone != null) { break; } } } if (zone == null) { logger.Error("Could not find DNS zone"); return(false); } ListResourceRecordSetsResponse txtRecordsResponse = route53Client.ListResourceRecordSets(new ListResourceRecordSetsRequest { StartRecordName = dnsKeyName, StartRecordType = "TXT", MaxItems = "1", HostedZoneId = zone.Id }); ResourceRecordSet txtRecord = txtRecordsResponse.ResourceRecordSets.FirstOrDefault(r => (r.Name == dnsKeyName || r.Name == dnsKeyName + ".") && r.Type.Value == "TXT"); if (txtRecord != null) { ApplyDnsChange(zone, txtRecord, ChangeAction.DELETE); } txtRecord = new ResourceRecordSet() { Name = dnsKeyName, TTL = 5, Type = RRType.TXT, ResourceRecords = new List <ResourceRecord> { new ResourceRecord { Value = "\"" + dnsKeyValue + "\"" } } }; ApplyDnsChange(zone, txtRecord, ChangeAction.UPSERT); } catch (AmazonRoute53Exception exp) { logger.Error($"Could not update AWS Route53 record: ", exp); return(false); } return(true); }