go-ldap / ldap

Basic LDAP v3 functionality for the GO programming language.
Other
2.24k stars 355 forks source link

server discovery by SRV record? #329

Open x3nb63 opened 3 years ago

x3nb63 commented 3 years ago

Since I don't find "SRV" with the search function I assume this is not supported?

I do have multiple LDAP servers running my domain - would be really good if the clients could be setup that way.

This is about RFC 2782, while its use with LDAP is better described by DNS SRV Records for LDAP

FreeIPA always creates these records (cause its clients depend on it) and I bet systems such as Active Directory do that as well.

johnweldon commented 3 years ago

I like this suggestion; feel free to pull together a PR. Otherwise I'll leave this hear as an enhancement request.

nf-brentsaner commented 8 months ago

Just pinging in here; Active Directory does indeed create SRV records as well.

I don't have a FreeIPA to play with at the moment, but I do have a function for the SRV lookups (below). Feel free to use, incorporate into the library, etc.

(@x3nb63 can you confirm that the FreeIPA SRV records use the same SRV name? I have no doubt that they don't, as it's an RFC (one of the authors is Paul Vixie himself!), but confirmation is good.)

import (
    "context"
    "fmt"
    "net"
    "net/url"

    "github.com/go-ldap/ldap/v3"
)

// ...

var (
    dnsCtx context.Context = context.Background()
)

func srvToUri(records []*net.SRV) (uris []*url.URL, err error) {

    var u *url.URL

    if records == nil {
        return
    }

    uris = make([]*url.URL, len(records))

    for idx, r := range records {
        uris[idx] = &url.URL{
            Scheme: "ldap",
            Host:   fmt.Sprintf("%v:%v", r.Target, r.Port),
        }
    }

    return
}

func ldapUriFromSrv(domain string, resolver net.Resolver) (uris []*url.URL, err error) {

    var srvRecords []*net.SRV

    if resolver == nil {
        resolver = net.DefaultResolver
    }

    if _, srvRecords, err = resolver.LookupSRV(dnsCtx, "ldap", "tcp", domain); err != nil {
        return
    }

    // There is no need to sort/shuffle records according to prio/weight;
    // the (net.Resolver).LookupSRV() method does this for us.

    if srvUris, dnsErr = srvToUri(srvRecords); err != nil {
        return
    }
}