summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2009-12-07 16:52:27 +0100
committerWerner Koch <wk@gnupg.org>2009-12-07 16:52:27 +0100
commit85d778b9f6fc37f1fae9c2d0dca6c3d51517dd21 (patch)
tree46ac431df3a7970a33bee257b79ea00d35bee2a0 /common
parentallow for default algorithms in a gpg parameter file (diff)
downloadgnupg2-85d778b9f6fc37f1fae9c2d0dca6c3d51517dd21.tar.xz
gnupg2-85d778b9f6fc37f1fae9c2d0dca6c3d51517dd21.zip
Use ADNS for PKA and SRV records if no other resolver is available.
Diffstat (limited to 'common')
-rw-r--r--common/ChangeLog7
-rw-r--r--common/pka.c71
-rw-r--r--common/srv.c382
3 files changed, 301 insertions, 159 deletions
diff --git a/common/ChangeLog b/common/ChangeLog
index e2da8a01a..6ec45823d 100644
--- a/common/ChangeLog
+++ b/common/ChangeLog
@@ -1,3 +1,10 @@
+2009-12-07 Werner Koch <wk@g10code.com>
+
+ * pka.c (get_pka_info): Add support for ADNS.
+ * src.v (getsrv): Add support for ADNS.
+
+ * srv.c (getsrv): s/xrealloc/xtryrealloc/.
+
2009-12-04 Werner Koch <wk@g10code.com>
* Makefile.am (audit-events.h, status-codes.h): Create files in
diff --git a/common/pka.c b/common/pka.c
index 79a0bc3f5..e78f54367 100644
--- a/common/pka.c
+++ b/common/pka.c
@@ -33,6 +33,12 @@
#include <resolv.h>
#endif
#endif /* USE_DNS_PKA */
+#ifdef USE_ADNS
+# include <adns.h>
+# ifndef HAVE_ADNS_FREE
+# define adns_free free
+# endif
+#endif
#include "util.h"
#include "pka.h"
@@ -106,6 +112,67 @@ parse_txt_record (char *buffer, unsigned char *fpr)
char *
get_pka_info (const char *address, unsigned char *fpr)
{
+#ifdef USE_ADNS
+ int rc;
+ adns_state state;
+ const char *domain;
+ char *name;
+ adns_answer *answer = NULL;
+ char *buffer = NULL;
+
+ domain = strrchr (address, '@');
+ if (!domain || domain == address || !domain[1])
+ return NULL; /* Invalid mail address given. */
+ name = xtrymalloc (strlen (address) + 5 + 1);
+ if (!name)
+ return NULL;
+ memcpy (name, address, domain - address);
+ strcpy (stpcpy (name + (domain-address), "._pka."), domain+1);
+
+ rc = adns_init (&state, adns_if_noerrprint, NULL);
+ if (rc)
+ {
+ log_error ("error initializing adns: %s\n", strerror (errno));
+ xfree (name);
+ return NULL;
+ }
+
+ rc = adns_synchronous (state, name, adns_r_txt, adns_qf_quoteok_query,
+ &answer);
+ xfree (name);
+ if (rc)
+ {
+ log_error ("DNS query failed: %s\n", strerror (errno));
+ adns_finish (state);
+ return NULL;
+ }
+ if (answer->status != adns_s_ok
+ || answer->type != adns_r_txt || !answer->nrrs)
+ {
+ log_error ("DNS query returned an error: %s (%s)\n",
+ adns_strerror (answer->status),
+ adns_errabbrev (answer->status));
+ adns_free (answer);
+ adns_finish (state);
+ return NULL;
+ }
+
+ /* We use a PKA records iff there is exactly one record. */
+ if (answer->nrrs == 1 && answer->rrs.manyistr[0]->i != -1)
+ {
+ buffer = xtrystrdup (answer->rrs.manyistr[0]->str);
+ if (parse_txt_record (buffer, fpr))
+ {
+ xfree (buffer);
+ buffer = NULL; /* Not a valid gpg trustdns RR. */
+ }
+ }
+
+ adns_free (answer);
+ adns_finish (state);
+ return buffer;
+
+#else /*!USE_ADNS*/
unsigned char answer[PACKETSZ];
int anslen;
int qdcount, ancount, nscount, arcount;
@@ -197,7 +264,9 @@ get_pka_info (const char *address, unsigned char *fpr)
}
return NULL;
+#endif /*!USE_ADNS*/
}
+
#else /* !USE_DNS_PKA */
/* Dummy version of the function if we can't use the resolver
@@ -247,6 +316,6 @@ main(int argc,char *argv[])
/*
Local Variables:
-compile-command: "cc -DUSE_DNS_PKA -DTEST -I.. -I../include -Wall -g -o pka pka.c -lresolv libutil.a"
+compile-command: "cc -DUSE_DNS_PKA -DTEST -I.. -I../include -Wall -g -o pka pka.c -lresolv ../tools/no-libgcrypt.o ../jnlib/libjnlib.a"
End:
*/
diff --git a/common/srv.c b/common/srv.c
index 46d84b583..79ffc7862 100644
--- a/common/srv.c
+++ b/common/srv.c
@@ -30,6 +30,12 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
+#ifdef USE_ADNS
+# include <adns.h>
+# ifndef HAVE_ADNS_FREE
+# define adns_free free
+# endif
+#endif
#include "util.h"
#include "srv.h"
@@ -52,172 +58,232 @@ priosort(const void *a,const void *b)
return 0;
}
+
int
-getsrv(const char *name,struct srventry **list)
+getsrv (const char *name,struct srventry **list)
{
- unsigned char answer[2048];
- int r,srvcount=0;
- unsigned char *pt,*emsg;
- u16 count,dlen;
- HEADER *header=(HEADER *)answer;
-
- *list=NULL;
+ int srvcount=0;
+ u16 count;
+ int i, rc;
+
+ *list = NULL;
+
+#ifdef USE_ADNS
+ {
+ adns_state state;
+ adns_answer *answer = NULL;
+
+ rc = adns_init (&state, adns_if_noerrprint, NULL);
+ if (rc)
+ {
+ log_error ("error initializing adns: %s\n", strerror (errno));
+ return -1;
+ }
+
+ rc = adns_synchronous (state, name, adns_r_srv, adns_qf_quoteok_query,
+ &answer);
+ if (rc)
+ {
+ log_error ("DNS query failed: %s\n", strerror (errno));
+ adns_finish (state);
+ return -1;
+ }
+ if (answer->status != adns_s_ok
+ || answer->type != adns_r_srv || !answer->nrrs)
+ {
+ log_error ("DNS query returned an error or no records: %s (%s)\n",
+ adns_strerror (answer->status),
+ adns_errabbrev (answer->status));
+ adns_free (answer);
+ adns_finish (state);
+ return 0;
+ }
+
+ for (count = 0; count < answer->nrrs; count++)
+ {
+ struct srventry *srv = NULL;
+ struct srventry *newlist;
+
+ if (strlen (answer->rrs.srvha[count].ha.host) >= MAXDNAME)
+ {
+ log_info ("hostname in SRV record too long - skipped\n");
+ continue;
+ }
+
+ newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry));
+ if (!newlist)
+ goto fail;
+ *list = newlist;
+ memset (&(*list)[srvcount], 0, sizeof(struct srventry));
+ srv = &(*list)[srvcount];
+ srvcount++;
+
+ srv->priority = answer->rrs.srvha[count].priority;
+ srv->weight = answer->rrs.srvha[count].weight;
+ srv->port = answer->rrs.srvha[count].port;
+ strcpy (srv->target, answer->rrs.srvha[count].ha.host);
+ }
+
+ adns_free (answer);
+ adns_finish (state);
+ }
+#else /*!USE_ADNS*/
+ {
+ unsigned char answer[2048];
+ HEADER *header = (HEADER *)answer;
+ unsigned char *pt, *emsg;
+ int r;
+ u16 dlen;
+
+ r = res_query (name, C_IN, T_SRV, answer, sizeof answer);
+ if (r < sizeof (HEADER) || r > sizeof answer)
+ return -1;
+ if (header->rcode != NOERROR || !(count=ntohs (header->ancount)))
+ return 0; /* Error or no record found. */
+
+ emsg = &answer[r];
+ pt = &answer[sizeof(HEADER)];
+
+ /* Skip over the query */
+ rc = dn_skipname (pt, emsg);
+ if (rc == -1)
+ goto fail;
+
+ pt += rc + QFIXEDSZ;
+
+ while (count-- > 0 && pt < emsg)
+ {
+ struct srventry *srv=NULL;
+ u16 type,class;
+ struct srventry *newlist;
+
+ newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry));
+ if (!newlist)
+ goto fail;
+ *list = newlist;
+ memset(&(*list)[srvcount],0,sizeof(struct srventry));
+ srv=&(*list)[srvcount];
+ srvcount++;
+
+ rc = dn_skipname(pt,emsg); /* the name we just queried for */
+ if (rc == -1)
+ goto fail;
+ pt+=rc;
+
+ /* Truncated message? */
+ if((emsg-pt)<16)
+ goto fail;
+
+ type=*pt++ << 8;
+ type|=*pt++;
+ /* We asked for SRV and got something else !? */
+ if(type!=T_SRV)
+ goto fail;
+
+ class=*pt++ << 8;
+ class|=*pt++;
+ /* We asked for IN and got something else !? */
+ if(class!=C_IN)
+ goto fail;
+
+ pt+=4; /* ttl */
+ dlen=*pt++ << 8;
+ dlen|=*pt++;
+ srv->priority=*pt++ << 8;
+ srv->priority|=*pt++;
+ srv->weight=*pt++ << 8;
+ srv->weight|=*pt++;
+ srv->port=*pt++ << 8;
+ srv->port|=*pt++;
+
+ /* Get the name. 2782 doesn't allow name compression, but
+ dn_expand still works to pull the name out of the
+ packet. */
+ rc = dn_expand(answer,emsg,pt,srv->target,MAXDNAME);
+ if (rc == 1 && srv->target[0] == 0) /* "." */
+ {
+ xfree(*list);
+ *list = NULL;
+ return 0;
+ }
+ if (rc == -1)
+ goto fail;
+ pt += rc;
+ /* Corrupt packet? */
+ if (dlen != rc+6)
+ goto fail;
+ }
+ }
+#endif /*!USE_ADNS*/
+
+ /* Now we have an array of all the srv records. */
+
+ /* Order by priority */
+ qsort(*list,srvcount,sizeof(struct srventry),priosort);
+
+ /* For each priority, move the zero-weighted items first. */
+ for (i=0; i < srvcount; i++)
+ {
+ int j;
+
+ for (j=i;j < srvcount && (*list)[i].priority == (*list)[j].priority; j++)
+ {
+ if((*list)[j].weight==0)
+ {
+ /* Swap j with i */
+ if(j!=i)
+ {
+ struct srventry temp;
+
+ memcpy (&temp,&(*list)[j],sizeof(struct srventry));
+ memcpy (&(*list)[j],&(*list)[i],sizeof(struct srventry));
+ memcpy (&(*list)[i],&temp,sizeof(struct srventry));
+ }
+
+ break;
+ }
+ }
+ }
- r=res_query(name,C_IN,T_SRV,answer,2048);
- if(r<sizeof(HEADER) || r>2048)
- return -1;
+ /* Run the RFC-2782 weighting algorithm. We don't need very high
+ quality randomness for this, so regular libc srand/rand is
+ sufficient. Fixme: It is a bit questionaly to reinitalize srand
+ - better use a gnupg fucntion for this. */
+ srand(time(NULL)*getpid());
- if(header->rcode==NOERROR && (count=ntohs(header->ancount)))
+ for (i=0; i < srvcount; i++)
{
- int i,rc;
-
- emsg=&answer[r];
- pt=&answer[sizeof(HEADER)];
-
- /* Skip over the query */
-
- rc=dn_skipname(pt,emsg);
- if(rc==-1)
- goto fail;
-
- pt+=rc+QFIXEDSZ;
-
- while(count-->0 && pt<emsg)
- {
- struct srventry *srv=NULL;
- u16 type,class;
-
- *list=xrealloc(*list,(srvcount+1)*sizeof(struct srventry));
- memset(&(*list)[srvcount],0,sizeof(struct srventry));
- srv=&(*list)[srvcount];
- srvcount++;
-
- rc=dn_skipname(pt,emsg); /* the name we just queried for */
- if(rc==-1)
- goto fail;
- pt+=rc;
-
- /* Truncated message? */
- if((emsg-pt)<16)
- goto fail;
-
- type=*pt++ << 8;
- type|=*pt++;
- /* We asked for SRV and got something else !? */
- if(type!=T_SRV)
- goto fail;
-
- class=*pt++ << 8;
- class|=*pt++;
- /* We asked for IN and got something else !? */
- if(class!=C_IN)
- goto fail;
-
- pt+=4; /* ttl */
- dlen=*pt++ << 8;
- dlen|=*pt++;
- srv->priority=*pt++ << 8;
- srv->priority|=*pt++;
- srv->weight=*pt++ << 8;
- srv->weight|=*pt++;
- srv->port=*pt++ << 8;
- srv->port|=*pt++;
-
- /* Get the name. 2782 doesn't allow name compression, but
- dn_expand still works to pull the name out of the
- packet. */
- rc=dn_expand(answer,emsg,pt,srv->target,MAXDNAME);
- if(rc==1 && srv->target[0]==0) /* "." */
- goto noanswer;
- if(rc==-1)
- goto fail;
- pt+=rc;
- /* Corrupt packet? */
- if(dlen!=rc+6)
- goto fail;
-
-#if 0
- printf("count=%d\n",srvcount);
- printf("priority=%d\n",srv->priority);
- printf("weight=%d\n",srv->weight);
- printf("port=%d\n",srv->port);
- printf("target=%s\n",srv->target);
-#endif
- }
-
- /* Now we have an array of all the srv records. */
-
- /* Order by priority */
- qsort(*list,srvcount,sizeof(struct srventry),priosort);
-
- /* For each priority, move the zero-weighted items first. */
- for(i=0;i<srvcount;i++)
- {
- int j;
-
- for(j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++)
- {
- if((*list)[j].weight==0)
- {
- /* Swap j with i */
- if(j!=i)
- {
- struct srventry temp;
-
- memcpy(&temp,&(*list)[j],sizeof(struct srventry));
- memcpy(&(*list)[j],&(*list)[i],sizeof(struct srventry));
- memcpy(&(*list)[i],&temp,sizeof(struct srventry));
- }
-
- break;
- }
- }
- }
-
- /* Run the RFC-2782 weighting algorithm. We don't need very
- high quality randomness for this, so regular libc srand/rand
- is sufficient. */
- srand(time(NULL)*getpid());
-
- for(i=0;i<srvcount;i++)
- {
- int j;
- float prio_count=0,chose;
-
- for(j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++)
- {
- prio_count+=(*list)[j].weight;
- (*list)[j].run_count=prio_count;
- }
-
- chose=prio_count*rand()/RAND_MAX;
-
- for(j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++)
- {
- if(chose<=(*list)[j].run_count)
- {
- /* Swap j with i */
- if(j!=i)
- {
- struct srventry temp;
-
- memcpy(&temp,&(*list)[j],sizeof(struct srventry));
- memcpy(&(*list)[j],&(*list)[i],sizeof(struct srventry));
- memcpy(&(*list)[i],&temp,sizeof(struct srventry));
- }
- break;
- }
- }
- }
+ int j;
+ float prio_count=0,chose;
+
+ for (j=i; j < srvcount && (*list)[i].priority == (*list)[j].priority; j++)
+ {
+ prio_count+=(*list)[j].weight;
+ (*list)[j].run_count=prio_count;
+ }
+
+ chose=prio_count*rand()/RAND_MAX;
+
+ for (j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++)
+ {
+ if (chose<=(*list)[j].run_count)
+ {
+ /* Swap j with i */
+ if(j!=i)
+ {
+ struct srventry temp;
+
+ memcpy(&temp,&(*list)[j],sizeof(struct srventry));
+ memcpy(&(*list)[j],&(*list)[i],sizeof(struct srventry));
+ memcpy(&(*list)[i],&temp,sizeof(struct srventry));
+ }
+ break;
+ }
+ }
}
return srvcount;
- noanswer:
- xfree(*list);
- *list=NULL;
- return 0;
-
fail:
xfree(*list);
*list=NULL;
@@ -250,6 +316,6 @@ main(int argc,char *argv[])
/*
Local Variables:
-compile-command: "cc -DTEST -I.. -I../include -Wall -g -o srv srv.c -lresolv libutil.a"
+compile-command: "cc -DTEST -I.. -I../include -Wall -g -o srv srv.c -lresolv ../tools/no-libgcrypt.o ../jnlib/libjnlib.a"
End:
*/