/// <summary> /// Resolves X509 certificates for a specific subject. May either be an address or a domain name. /// </summary> /// <param name="srvRecord">Resolve <see cref="SRVRecord"/> to resolve. </param> /// /// <param name="subjectName">The <see cref="String"/> subject to resolve. </param> /// <returns>An <see cref="X509Certificate2Collection"/> of X509 certifiates for the address, /// or <c>null</c> if no certificates are found.</returns> X509Certificate2Collection GetCertificatesBySubect(SRVRecord srvRecord, string subjectName) { var retVal = new X509Certificate2Collection(); // get the LDAP connection from the SRV records using (var connection = GetLdapConnection(srvRecord)) { if (connection != null) { // gate the base naming contexts var distNames = GetBaseNamingContext(connection); foreach (var dn in distNames) { // search each base context var request = Search.MimeCertRequest(dn, subjectName); try { SetCerts(connection, request, retVal); } catch (LdapCertResolverException ldapEx) { this.Error.NotifyEvent(this, new LdapCertResolverException(ldapEx.Error, subjectName + srvRecord, ldapEx.InnerException)); } catch (Exception ex) { this.Error.NotifyEvent(this, ex); } } } } return(retVal); }
/// <summary> /// Creates a connection to an LDAP server based on the DNS SRV resolution of the lookup name. /// </summary> /// <param name="srvRecord">Resolver <see cref="SRVRecord"/></param> /// <returns>An <see cref="LdapConnection"/> to the server that will be searched for certificates.</returns> protected LdapConnection GetLdapConnection(SRVRecord srvRecord) { LdapConnection retVal; var ldapIdentifier = new LdapDirectoryIdentifier(srvRecord.Target, srvRecord.Port); try { retVal = new LdapConnection(ldapIdentifier); retVal.AuthType = AuthType.Anonymous; // use anonymous bind retVal.SessionOptions.ProtocolVersion = LdapProtoVersion; if (Timeout.Ticks > 0) { retVal.Timeout = Timeout; } retVal.Bind(); } catch (Exception ex) { // didn't connenct.... go onto the next record this.Error.NotifyEvent(this, new LdapCertResolverException(LDAPError.BindFailure, srvRecord.ToString(), ex)); retVal = null; } return(retVal); }
/// <summary> /// Look up a DNS SRV record, returning the best host and port number to connect to. /// </summary> /// <param name="prefix">The SRV prefix, ending with a dot. Example: "_xmpp-client._tcp."</param> /// <param name="domain">The domain to check</param> /// <param name="host">The host name to connect to</param> /// <param name="port">The port number to connect to</param> public static void LookupSRV(string prefix, string domain, ref string host, ref int port) { if (prefix == null) { throw new ArgumentNullException("prefix"); } if (domain == null) { throw new ArgumentNullException("domain"); } if (!prefix.EndsWith(".")) { throw new ArgumentOutOfRangeException("Prefix must end in '.'", "prefix"); } try { DnsRequest request = new DnsRequest(prefix + domain); DnsResponse response = request.GetResponse(DnsRecordType.SRV); SRVRecord record = PickSRV(response.SRVRecords); host = record.NameNext; port = record.Port; Debug.WriteLine(string.Format("SRV found: {0}:{1}", host, port)); } catch { host = domain; } }
// private, constructor initialised fields /// <summary> /// Construct a resource record from a pointer to a byte array /// </summary> /// <param name="pointer">the position in the byte array of the record</param> internal ResourceRecord(Pointer pointer) { // extract the domain, question type, question class and Ttl Domain = pointer.ReadDomain(); Type = (DnsType)pointer.ReadShort(); Class = (DnsClass)pointer.ReadShort(); Ttl = pointer.ReadInt(); // the next short is the record length, we only use it for unrecognised record types int recordLength = pointer.ReadShort(); // and create the appropriate RDATA record based on the dnsType switch (Type) { case DnsType.SRV: Record = new SRVRecord(pointer); break; default: { // move the pointer over this unrecognised record pointer.Position += recordLength; break; } } }
/// <summary> /// Look up a DNS SRV record, returning the best host and port number to connect to. /// </summary> /// <param name="prefix">The SRV prefix, ending with a dot. Example: "_xmpp-client._tcp."</param> /// <param name="domain">The domain to check</param> /// <param name="host">The host name to connect to</param> /// <param name="port">The port number to connect to</param> public static void LookupSRV(string prefix, string domain, ref string host, ref int port) { if (prefix == null) { throw new ArgumentNullException("prefix"); } if (domain == null) { throw new ArgumentNullException("domain"); } if (!prefix.EndsWith(".")) { throw new ArgumentOutOfRangeException("Prefix must end in '.'", "prefix"); } try { IList <SRVRecord> srvRecords = DnsServiceFactory.Create().GetSrvRecords(prefix + domain); SRVRecord record = PickSRV(srvRecords.ToArray()); host = record.NameNext; port = record.Port; Debug.WriteLine(string.Format("SRV found: {0}:{1}", host, port)); } catch { host = domain; } }
private void AnswerReceived(Message message) { List <PTRRecord> answers = message.Answers.Where(a => a.Name == AtemDeviceInfo.ServiceName).OfType <PTRRecord>().ToList(); PTRRecord answer = answers.FirstOrDefault(); if (answer == null) { return; } if (_debug && answers.Count != 1) { Console.WriteLine("Too many answers!"); } List <ResourceRecord> records = message.AdditionalRecords; SRVRecord srvRec = records.OfType <SRVRecord>().FirstOrDefault(r => r.Type == DnsType.SRV && r.Name == answer.DomainName); if (srvRec == null) { if (_debug) { Console.WriteLine("Missing SRV record for " + answer.DomainName); } return; } AddressRecord aRec = records.OfType <AddressRecord>().FirstOrDefault(r => r.Type == DnsType.A && r.Name == srvRec.Target); if (aRec == null) { if (_debug) { Console.WriteLine("Missing A record for " + answer.DomainName); } return; } TXTRecord txtRec = records.OfType <TXTRecord>().FirstOrDefault(r => r.Type == DnsType.TXT && r.Name == answer.DomainName); List <string> strings = txtRec == null ? new List <string>() : txtRec.Strings; string name = string.Join(".", answer.DomainName.Labels); if (name.EndsWith(AtemDeviceInfo.ServiceName)) { name = name.Substring(0, name.Length - AtemDeviceInfo.ServiceName.Length - 1); } var dev = new AtemDeviceInfo(name, srvRec.Target.ToString(), DateTime.Now, aRec.Address.ToString(), srvRec.Port, strings); lock (_knownDevices) { _knownDevices[dev.DeviceId] = dev; } OnDeviceSeen?.Invoke(this, dev); }
private static SRVRecord PickSRV(SRVRecord[] srv) { // TODO: keep track of connection failures, and try the next priority down. if ((srv == null) || (srv.Length == 0)) throw new ArgumentException(); if (srv.Length == 1) return srv[0]; // randomize order. One might wish that the OS would have done this for us. // cf. Bob Schriter's Grandfather. Random rnd = new Random(); byte[] keys = new byte[srv.Length]; rnd.NextBytes(keys); Array.Sort(keys, srv); // Permute me, Knuth! (I wish I had a good anagram for that) int minpri = int.MaxValue; foreach (SRVRecord rec in srv) { if (rec.Priority < minpri) { minpri = rec.Priority; } } int weight = 0; foreach (SRVRecord rec in srv) { if (rec.Priority == minpri) { weight += rec.Weight; } } int pos = rnd.Next(weight); weight = 0; foreach (SRVRecord rec in srv) { if (rec.Priority == minpri) { weight += rec.Weight; if ((pos < weight) || (weight == 0)) { return rec; } } } throw new DnsException("No matching SRV"); }
private void ParseRecords(List <ResourceRecord> records) { foreach (ResourceRecord record in records) { if (record is SRVRecord) { if (!((SRVRecord)record).Name.ToString().Contains("_" + this.tag)) { continue; } this.srvRec = (SRVRecord)record; this.ForMe = true; } } }
private void SetCerts(SRVRecord srvRecord, LdapConnection connection, List <string> distNames, string subject, X509Certificate2Collection retVal) { foreach (var dn in distNames) { // search each base context try { var request = Search.MimeCertRequest(dn, subject); SetCerts(connection, request, retVal, srvRecord, subject); } catch (Exception ex) { Error.NotifyEvent(this, ex); } } }
public DnsRecord ParseSRV(string[] args) { string domainName = args.GetRequiredValue(0); ushort weight = args.GetRequiredValue <ushort>(1); ushort port = args.GetRequiredValue <ushort>(2); string target = args.GetRequiredValue(3); //target ushort priority = args.GetOptionalValue <ushort>(4, 0); int ttl = this.ValidateTTL(args.GetOptionalValue <int>(5, 0)); string notes = args.GetOptionalValue(6, string.Empty); SRVRecord srvRecord = new SRVRecord(domainName, weight, port, target, priority) { TTL = ttl }; DnsRecord dnsRecord = new DnsRecord(domainName, DnsStandard.RecordType.SRV, srvRecord.Serialize(), notes); return(dnsRecord); }
private String ParseDNSAnswer(Dictionary <DnsType, ResourceRecord> answer) { Console.WriteLine("Parse the DNS Answer"); if ((answer.ContainsKey(DnsType.A) || answer.ContainsKey(DnsType.AAAA)) && answer.ContainsKey(DnsType.SRV) && answer.ContainsKey(DnsType.TXT)) { TXTRecord txt_item = answer[DnsType.TXT] as TXTRecord; Dictionary <String, String> text_dic = new Dictionary <String, String>(); foreach (String item in txt_item.Strings) { String[] item_split = item.Split("="); text_dic.Add(item_split[0], item_split[1]); } if (text_dic.ContainsKey("td")) { Console.WriteLine($"{txt_item.Type}: " + $"'{txt_item.Name}' {String.Join(" ", txt_item.Strings.ToArray())}"); Boolean using_a = false; if (answer.ContainsKey(DnsType.A)) { using_a = true; } AddressRecord aa_item; if (using_a) { aa_item = answer[DnsType.A] as AddressRecord; Console.WriteLine($"{aa_item.Type}: " + $"host '{aa_item.Name}' at '{aa_item.Address}'"); } else { aa_item = answer[DnsType.AAAA] as AddressRecord; Console.WriteLine($"{aa_item.Type}: " + $"host '{aa_item.Name}' at '{aa_item.Address}'"); } SRVRecord srv_item = answer[DnsType.SRV] as SRVRecord; Console.WriteLine($"{srv_item.Type}: " + $"service '{srv_item.Name}' on '{srv_item.Target}' at '{srv_item.Port}'"); String ret = $"http://{aa_item.Address}:{srv_item.Port}{text_dic["td"]}"; Console.WriteLine($"Combine Answer to {ret}\n"); return(ret); } } return(""); }
private NetService ProcessSRVRecord(SRVRecord record) { string serviceInstanceName = record.Name; if (_discoveredServices.ContainsKey(serviceInstanceName)) { NetService service = _discoveredServices[serviceInstanceName]; service.Hostname = record.Target; service.Port = record.Port; service.IPAddresses.Clear(); if (_discoveredIPs.ContainsKey(service.Hostname)) { service.IPAddresses.AddRange(_discoveredIPs[service.Hostname]); } return(service); } return(null); }
/// <summary> /// Resolves X509 certificates for a specific subject. By domain name. /// </summary> /// <param name="connection">Active LDAP connection</param> /// <param name="srvRecord">Resolve <see cref="SRVRecord"/> to resolve. </param> /// /// <param name="domain">The <see cref="String"/> domain to resolve. </param> /// <returns>An <see cref="X509Certificate2Collection"/> of X509 certifiates for the address, /// or <c>null</c> if no certificates are found.</returns> X509Certificate2Collection GetCertificatesByDomain(LdapConnection connection, SRVRecord srvRecord, string domain) { var retVal = new X509Certificate2Collection(); // gate the base naming contexts var distNames = GetBaseNamingContext(connection); SetCerts(srvRecord, connection, distNames, domain, retVal); return(retVal); }
private Message GetPublishMessage(PublishMessageType type) { Message message = new Message(); ResourceRecord record; // This message is a response message.QueryResponse = true; // This is an authoritative response message.AuthoritativeAnswer = true; // SRV Record record = new SRVRecord() { TimeToLive = (type == PublishMessageType.Stop) ? TimeSpan.Zero : BroadcastTTL, CacheFlush = true, Name = FullServiceInstanceName, Target = Hostname, Port = Port, }; message.AnswerRecords.Add(record); // TXT Record if (TXTRecordData != null && TXTRecordData.Count > 0) { record = new TXTRecord() { TimeToLive = (type == PublishMessageType.Stop) ? TimeSpan.Zero : BroadcastTTL, CacheFlush = true, Name = FullServiceInstanceName, Data = TXTRecordData, }; message.AnswerRecords.Add(record); } // PTR Record for DNS-SD Service Type Enumeration if (type == PublishMessageType.Normal) { record = new PTRRecord() { TimeToLive = BroadcastTTL, Name = BonjourUtility.DNSSDServiceTypeEnumerationName, DomainName = Type, }; message.AnswerRecords.Add(record); } // Service PTR Record if (type != PublishMessageType.Initial) { record = new PTRRecord() { TimeToLive = (type == PublishMessageType.Stop) ? TimeSpan.Zero : BroadcastTTL, Name = Type, DomainName = FullServiceInstanceName, }; message.AnswerRecords.Add(record); } // A Records if (type != PublishMessageType.Stop) { foreach (var ip in IPAddresses) { record = new ARecord() { TimeToLive = BroadcastTTL, CacheFlush = true, Name = Hostname, Address = ip, }; message.AdditionalRecords.Add(record); } } return(message); }
private void SetCerts(LdapConnection connection, SearchRequest request, X509Certificate2Collection retVal, SRVRecord srvRecord, string subjectName) { // send the LDAP request using the mail attribute as the search filter and return the userCertificate attribute var response = (SearchResponse)connection.SendRequest(request); if (response != null && response.Entries.Count > 0) { foreach (SearchResultEntry entry in response.Entries) { SetCerts(entry, retVal, srvRecord, subjectName); } } }
private void SetCerts(SearchResultEntry entry, X509Certificate2Collection retVal, SRVRecord srvRecord, string subjectName) { if (entry.Attributes.Values == null || entry.Attributes.Count <= 0) { StringBuilder sb = new StringBuilder(); sb.Append(subjectName).Append(" SRV:").Append(srvRecord).Append(" LDAP:").Append(entry.DistinguishedName); Error.NotifyEvent(this, new LdapCertResolverException(LDAPError.NoUserCertificateAttribute, sb.ToString())); return; } foreach (DirectoryAttribute entryAttr in entry.Attributes.Values) { if (entryAttr.Count > 0) { // search could possibly return more than one entry and each entry may contain // more that one certificates foreach (object t in entryAttr) { try { var cert = new X509Certificate2((byte[])t); retVal.Add(cert); } catch (Exception ex) { Error.NotifyEvent(this, ex); } } } } }
public static SRVRecord[] ResolveSRV(string query) { byte[] buffer = new byte[1024]; byte[] name = new byte[256]; ushort type, dlen, priority, weight, port; int size; GCHandle handle; List <SRVRecord> results = new List <SRVRecord>(); size = res_query(query, C_IN, T_SRV, buffer, buffer.Length); handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); try { HEADER header = (HEADER)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(HEADER)); int qdcount = ntohs(header.qdcount); int ancount = ntohs(header.ancount); int headerSize = Marshal.SizeOf(header); unsafe { fixed(byte *pBuffer = buffer) { byte *pos = pBuffer + headerSize; byte *end = pBuffer + size; // We don't care about the question section. while (qdcount-- > 0 && pos < end) { size = dn_expand(pBuffer, end, pos, name, 256); if (size < 0) { return(null); } pos += size + 4; } // The answers, however, we do care about! while (ancount-- > 0 && pos < end) { size = dn_expand(pBuffer, end, pos, name, 256); if (size < 0) { return(null); } pos += size; type = GETSHORT(ref pos); // Skip TTL pos += 6; dlen = GETSHORT(ref pos); if (type == T_SRV) { priority = GETSHORT(ref pos); weight = GETSHORT(ref pos); port = GETSHORT(ref pos); size = dn_expand(pBuffer, end, pos, name, 256); if (size < 0) { return(null); } string nameStr = null; fixed(byte *pName = name) { nameStr = new String((sbyte *)pName); } var record = new SRVRecord(); record.NameNext = nameStr; record.Priority = priority; record.Weight = weight; record.Port = port; results.Add(record); pos += size; } else { pos += dlen; } } } } } finally { handle.Free(); } return(results.ToArray()); }
/// <summary> /// Resolves X509 certificates for a specific subject. Will search address and then domain. /// </summary> /// <param name="connection">Active LDAP connection</param> /// <param name="srvRecord">Resolve <see cref="SRVRecord"/> to resolve. </param> /// /// <param name="address">The <see cref="String"/> address to resolve. </param> /// <returns>An <see cref="X509Certificate2Collection"/> of X509 certifiates for the address, /// or <c>null</c> if no certificates are found.</returns> X509Certificate2Collection GetCertificatesBySubect(LdapConnection connection, SRVRecord srvRecord, MailAddress address) { var retVal = new X509Certificate2Collection(); // gate the base naming contexts var distNames = GetBaseNamingContext(connection); SetCerts(srvRecord, connection, distNames, address.Address, retVal); if (retVal.Count == 0) { SetCerts(srvRecord, connection, distNames, address.Host, retVal); } return(retVal); }
public static SRVRecord[] ResolveSRV(string query) { byte[] buffer = new byte[1024]; byte[] name = new byte[256]; ushort type, dlen, priority, weight, port; int size; GCHandle handle; List<SRVRecord> results = new List<SRVRecord>(); size = res_query(query, C_IN, T_SRV, buffer, buffer.Length); handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); try { HEADER header = (HEADER)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(HEADER)); int qdcount = ntohs(header.qdcount); int ancount = ntohs(header.ancount); int headerSize = Marshal.SizeOf(header); unsafe { fixed (byte* pBuffer = buffer) { byte *pos = pBuffer + headerSize; byte *end = pBuffer + size; // We don't care about the question section. while (qdcount-- > 0 && pos < end) { size = dn_expand(pBuffer, end, pos, name, 256); if (size < 0) return null; pos += size + 4; } // The answers, however, we do care about! while (ancount-- > 0 && pos < end) { size = dn_expand(pBuffer, end, pos, name, 256); if (size < 0) return null; pos += size; type = GETSHORT(ref pos); // Skip TTL pos += 6; dlen = GETSHORT(ref pos); if (type == T_SRV) { priority = GETSHORT(ref pos); weight = GETSHORT(ref pos); port = GETSHORT(ref pos); size = dn_expand(pBuffer, end, pos, name, 256); if (size < 0) return null; string nameStr = null; fixed (byte* pName = name) { nameStr = new String((sbyte*)pName); } var record = new SRVRecord(); record.NameNext = nameStr; record.Priority = priority; record.Weight = weight; record.Port = port; results.Add(record); pos += size; } else { pos += dlen; } } } } } finally { handle.Free(); } return results.ToArray(); }