/* If there is a SRV record, take the highest ranked possibility. This is a hack, as we don't proceed downwards. */ static void srv_replace(const char *srvtag) { #ifdef USE_DNS_SRV struct srventry *srvlist=NULL; if(!srvtag) return; if(1+strlen(srvtag)+6+strlen(opt->host)+1<=MAXDNAME) { char srvname[MAXDNAME]; strcpy(srvname,"_"); strcat(srvname,srvtag); strcat(srvname,"._tcp."); strcat(srvname,opt->host); getsrv(srvname,&srvlist); } if(srvlist) { char *newname,*newport; newname=strdup(srvlist->target); newport=xtrymalloc(MAX_PORT); if(newname && newport) { free(opt->host); free(opt->port); opt->host=newname; snprintf(newport,MAX_PORT,"%u",srvlist->port); opt->port=newport; } else { free(newname); free(newport); } } #endif }
int main(int argc,char *argv[]) { struct srventry *srv; int rc,i; rc=getsrv("_hkp._tcp.wwwkeys.pgp.net",&srv); printf("Count=%d\n\n",rc); for(i=0;i<rc;i++) { printf("priority=%hu\n",srv[i].priority); printf("weight=%hu\n",srv[i].weight); printf("port=%hu\n",srv[i].port); printf("target=%s\n",srv[i].target); printf("\n"); } xfree(srv); return 0; }
/* Import a key by name using LDAP */ int keyserver_import_ldap (ctrl_t ctrl, const char *name,unsigned char **fpr,size_t *fpr_len) { char *domain; struct keyserver_spec *keyserver; strlist_t list=NULL; int rc,hostlen=1; #ifdef USE_DNS_SRV struct srventry *srvlist=NULL; int srvcount,i; char srvname[MAXDNAME]; #endif /* Parse out the domain */ domain=strrchr(name,'@'); if(!domain) return G10ERR_GENERAL; domain++; keyserver=xmalloc_clear(sizeof(struct keyserver_spec)); keyserver->scheme=xstrdup("ldap"); keyserver->host=xmalloc(1); keyserver->host[0]='\0'; #ifdef USE_DNS_SRV snprintf(srvname,MAXDNAME,"_pgpkey-ldap._tcp.%s",domain); srvcount=getsrv(srvname,&srvlist); for(i=0;i<srvcount;i++) { hostlen+=strlen(srvlist[i].target)+1; keyserver->host=xrealloc(keyserver->host,hostlen); strcat(keyserver->host,srvlist[i].target); if(srvlist[i].port!=389) { char port[7]; hostlen+=6; /* a colon, plus 5 digits (unsigned 16-bit value) */ keyserver->host=xrealloc(keyserver->host,hostlen); snprintf(port,7,":%u",srvlist[i].port); strcat(keyserver->host,port); } strcat(keyserver->host," "); } free(srvlist); #endif /* If all else fails, do the PGP Universal trick of ldap://keys.(domain) */ hostlen+=5+strlen(domain); keyserver->host=xrealloc(keyserver->host,hostlen); strcat(keyserver->host,"keys."); strcat(keyserver->host,domain); append_to_strlist(&list,name); rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED); /*FIXME*/ /* keyserver_work (ctrl, KS_GETNAME, list, NULL, */ /* 0, fpr, fpr_len, keyserver); */ free_strlist(list); free_keyserver_spec(keyserver); return rc; }
/* Map the host name NAME to the actual to be used host name. This allows us to manage round robin DNS names. We use our own strategy to choose one of the hosts. For example we skip those hosts which failed for some time and we stick to one host for a time independent of DNS retry times. If FORCE_RESELECT is true a new host is always selected. The selected host is stored as a malloced string at R_HOST; on error NULL is stored. If we know the port used by the selected host, a string representation is written to R_PORTSTR, otherwise it is left untouched. If R_HTTPFLAGS is not NULL it will receive flags which are to be passed to http_open. If R_POOLNAME is not NULL a malloced name of the pool is stored or NULL if it is not a pool. */ static gpg_error_t map_host (ctrl_t ctrl, const char *name, int force_reselect, char **r_host, char *r_portstr, unsigned int *r_httpflags, char **r_poolname) { gpg_error_t err = 0; hostinfo_t hi; int idx; *r_host = NULL; if (r_httpflags) *r_httpflags = 0; if (r_poolname) *r_poolname = NULL; /* No hostname means localhost. */ if (!name || !*name) { *r_host = xtrystrdup ("localhost"); return *r_host? 0 : gpg_error_from_syserror (); } /* See whether the host is in our table. */ idx = find_hostinfo (name); if (idx == -1 && is_onion_address (name)) { idx = create_new_hostinfo (name); if (idx == -1) return gpg_error_from_syserror (); hi = hosttable[idx]; hi->onion = 1; } else if (idx == -1) { /* We never saw this host. Allocate a new entry. */ dns_addrinfo_t aibuf, ai; int *reftbl; size_t reftblsize; int refidx; int is_pool = 0; char *cname; #ifdef USE_DNS_SRV char *srvrecord; struct srventry *srvs; int srvscount; #endif /* USE_DNS_SRV */ reftblsize = 100; reftbl = xtrymalloc (reftblsize * sizeof *reftbl); if (!reftbl) return gpg_error_from_syserror (); refidx = 0; idx = create_new_hostinfo (name); if (idx == -1) { err = gpg_error_from_syserror (); xfree (reftbl); return err; } hi = hosttable[idx]; #ifdef USE_DNS_SRV /* Check for SRV records. */ srvrecord = xtryasprintf ("_hkp._tcp.%s", name); if (srvrecord == NULL) { err = gpg_error_from_syserror (); xfree (reftbl); return err; } srvscount = getsrv (srvrecord, &srvs); xfree (srvrecord); if (srvscount < 0) { err = gpg_error_from_syserror (); xfree (reftbl); return err; } if (srvscount > 0) { int i; is_pool = srvscount > 1; for (i = 0; i < srvscount; i++) { err = resolve_dns_name (srvs[i].target, 0, AF_UNSPEC, SOCK_STREAM, &ai, &cname); if (err) continue; dirmngr_tick (ctrl); add_host (name, is_pool, ai, srvs[i].port, reftbl, reftblsize, &refidx); } xfree (srvs); } #endif /* USE_DNS_SRV */ /* Find all A records for this entry and put them into the pool list - if any. */ err = resolve_dns_name (name, 0, 0, SOCK_STREAM, &aibuf, &cname); if (err) { log_error ("resolving '%s' failed: %s\n", name, gpg_strerror (err)); err = 0; } else { /* First figure out whether this is a pool. For a pool we use a different strategy than for a plain server: We use the canonical name of the pool as the virtual host along with the IP addresses. If it is not a pool, we use the specified name. */ if (! is_pool) is_pool = arecords_is_pool (aibuf); if (is_pool && cname) { hi->cname = cname; cname = NULL; } for (ai = aibuf; ai; ai = ai->next) { if (ai->family != AF_INET && ai->family != AF_INET6) continue; dirmngr_tick (ctrl); add_host (name, is_pool, ai, 0, reftbl, reftblsize, &refidx); } } reftbl[refidx] = -1; xfree (cname); free_dns_addrinfo (aibuf); if (refidx && is_pool) { assert (!hi->pool); hi->pool = xtryrealloc (reftbl, (refidx+1) * sizeof *reftbl); if (!hi->pool) { err = gpg_error_from_syserror (); log_error ("shrinking index table in map_host failed: %s\n", gpg_strerror (err)); xfree (reftbl); return err; } qsort (hi->pool, refidx, sizeof *reftbl, sort_hostpool); } else xfree (reftbl); } hi = hosttable[idx]; if (hi->pool) { /* Deal with the pool name before selecting a host. */ if (r_poolname) { *r_poolname = xtrystrdup (hi->cname? hi->cname : hi->name); if (!*r_poolname) return gpg_error_from_syserror (); } /* If the currently selected host is now marked dead, force a re-selection . */ if (force_reselect) hi->poolidx = -1; else if (hi->poolidx >= 0 && hi->poolidx < hosttable_size && hosttable[hi->poolidx] && hosttable[hi->poolidx]->dead) hi->poolidx = -1; /* Select a host if needed. */ if (hi->poolidx == -1) { hi->poolidx = select_random_host (hi->pool); if (hi->poolidx == -1) { log_error ("no alive host found in pool '%s'\n", name); if (r_poolname) { xfree (*r_poolname); *r_poolname = NULL; } return gpg_error (GPG_ERR_NO_KEYSERVER); } } assert (hi->poolidx >= 0 && hi->poolidx < hosttable_size); hi = hosttable[hi->poolidx]; assert (hi); } if (hi->dead) { log_error ("host '%s' marked as dead\n", hi->name); if (r_poolname) { xfree (*r_poolname); *r_poolname = NULL; } return gpg_error (GPG_ERR_NO_KEYSERVER); } if (r_httpflags) { /* If the hosttable does not indicate that a certain host supports IPv<N>, we explicit set the corresponding http flags. The reason for this is that a host might be listed in a pool as not v6 only but actually support v6 when later the name is resolved by our http layer. */ if (!hi->v4) *r_httpflags |= HTTP_FLAG_IGNORE_IPv4; if (!hi->v6) *r_httpflags |= HTTP_FLAG_IGNORE_IPv6; /* Note that we do not set the HTTP_FLAG_FORCE_TOR for onion addresses because the http module detects this itself. This also allows us to use an onion address without Tor mode being enabled. */ } *r_host = xtrystrdup (hi->name); if (!*r_host) { err = gpg_error_from_syserror (); if (r_poolname) { xfree (*r_poolname); *r_poolname = NULL; } return err; } if (hi->port) snprintf (r_portstr, 6 /* five digits and the sentinel */, "%hu", hi->port); return 0; }