~ubuntu-branches/ubuntu/oneiric/gnupg2/oneiric-proposed

« back to all changes in this revision

Viewing changes to common/srv.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Bienia
  • Date: 2010-01-22 21:49:55 UTC
  • mfrom: (1.1.14 upstream) (7.1.3 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100122214955-r2ab5it9rts5gqjf
Tags: 2.0.14-1ubuntu1
* Merge with Debian testing (lp: #511356). Remaining changes:
  - debian/gnupg2.dev: udev rules to set ACLs on SCM smartcard readers.
  - debian/rules: Call dh_installudev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
#include <stdlib.h>
31
31
#include <string.h>
32
32
#include <time.h>
 
33
#ifdef USE_ADNS
 
34
# include <adns.h>
 
35
# ifndef HAVE_ADNS_FREE
 
36
#  define adns_free free
 
37
# endif
 
38
#endif
33
39
 
34
40
#include "util.h"
35
41
#include "srv.h"
52
58
    return 0;
53
59
}
54
60
 
 
61
 
55
62
int
56
 
getsrv(const char *name,struct srventry **list)
 
63
getsrv (const char *name,struct srventry **list)
57
64
{
58
 
  unsigned char answer[2048];
59
 
  int r,srvcount=0;
60
 
  unsigned char *pt,*emsg;
61
 
  u16 count,dlen;
62
 
  HEADER *header=(HEADER *)answer;
63
 
 
64
 
  *list=NULL;
65
 
 
66
 
  r=res_query(name,C_IN,T_SRV,answer,2048);
67
 
  if(r<sizeof(HEADER) || r>2048)
68
 
    return -1;
69
 
 
70
 
  if(header->rcode==NOERROR && (count=ntohs(header->ancount)))
71
 
    {
72
 
      int i,rc;
73
 
 
74
 
      emsg=&answer[r];
75
 
      pt=&answer[sizeof(HEADER)];
76
 
 
77
 
      /* Skip over the query */
78
 
 
79
 
      rc=dn_skipname(pt,emsg);
80
 
      if(rc==-1)
81
 
        goto fail;
82
 
 
83
 
      pt+=rc+QFIXEDSZ;
84
 
 
85
 
      while(count-->0 && pt<emsg)
86
 
        {
87
 
          struct srventry *srv=NULL;
88
 
          u16 type,class;
89
 
 
90
 
          *list=xrealloc(*list,(srvcount+1)*sizeof(struct srventry));
91
 
          memset(&(*list)[srvcount],0,sizeof(struct srventry));
92
 
          srv=&(*list)[srvcount];
93
 
          srvcount++;
94
 
 
95
 
          rc=dn_skipname(pt,emsg); /* the name we just queried for */
96
 
          if(rc==-1)
97
 
            goto fail;
98
 
          pt+=rc;
99
 
 
100
 
          /* Truncated message? */
101
 
          if((emsg-pt)<16)
102
 
            goto fail;
103
 
 
104
 
          type=*pt++ << 8;
105
 
          type|=*pt++;
106
 
          /* We asked for SRV and got something else !? */
107
 
          if(type!=T_SRV)
108
 
            goto fail;
109
 
 
110
 
          class=*pt++ << 8;
111
 
          class|=*pt++;
112
 
          /* We asked for IN and got something else !? */
113
 
          if(class!=C_IN)
114
 
            goto fail;
115
 
 
116
 
          pt+=4; /* ttl */
117
 
          dlen=*pt++ << 8;
118
 
          dlen|=*pt++;
119
 
          srv->priority=*pt++ << 8;
120
 
          srv->priority|=*pt++;
121
 
          srv->weight=*pt++ << 8;
122
 
          srv->weight|=*pt++;
123
 
          srv->port=*pt++ << 8;
124
 
          srv->port|=*pt++;
125
 
 
126
 
          /* Get the name.  2782 doesn't allow name compression, but
127
 
             dn_expand still works to pull the name out of the
128
 
             packet. */
129
 
          rc=dn_expand(answer,emsg,pt,srv->target,MAXDNAME);
130
 
          if(rc==1 && srv->target[0]==0) /* "." */
131
 
            goto noanswer;
132
 
          if(rc==-1)
133
 
            goto fail;
134
 
          pt+=rc;
135
 
          /* Corrupt packet? */
136
 
          if(dlen!=rc+6)
137
 
            goto fail;
138
 
 
139
 
#if 0
140
 
          printf("count=%d\n",srvcount);
141
 
          printf("priority=%d\n",srv->priority);
142
 
          printf("weight=%d\n",srv->weight);
143
 
          printf("port=%d\n",srv->port);
144
 
          printf("target=%s\n",srv->target);
145
 
#endif
146
 
        }
147
 
 
148
 
      /* Now we have an array of all the srv records. */
149
 
 
150
 
      /* Order by priority */
151
 
      qsort(*list,srvcount,sizeof(struct srventry),priosort);
152
 
 
153
 
      /* For each priority, move the zero-weighted items first. */
154
 
      for(i=0;i<srvcount;i++)
155
 
        {
156
 
          int j;
157
 
 
158
 
          for(j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++)
159
 
            {
160
 
              if((*list)[j].weight==0)
161
 
                {
162
 
                  /* Swap j with i */
163
 
                  if(j!=i)
164
 
                    {
165
 
                      struct srventry temp;
166
 
 
167
 
                      memcpy(&temp,&(*list)[j],sizeof(struct srventry));
168
 
                      memcpy(&(*list)[j],&(*list)[i],sizeof(struct srventry));
169
 
                      memcpy(&(*list)[i],&temp,sizeof(struct srventry));
170
 
                    }
171
 
 
172
 
                  break;
173
 
                }
174
 
            }
175
 
        }
176
 
 
177
 
      /* Run the RFC-2782 weighting algorithm.  We don't need very
178
 
         high quality randomness for this, so regular libc srand/rand
179
 
         is sufficient. */
180
 
      srand(time(NULL)*getpid());
181
 
 
182
 
      for(i=0;i<srvcount;i++)
183
 
        {
184
 
          int j;
185
 
          float prio_count=0,chose;
186
 
 
187
 
          for(j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++)
188
 
            {
189
 
              prio_count+=(*list)[j].weight;
190
 
              (*list)[j].run_count=prio_count;
191
 
            }
192
 
 
193
 
          chose=prio_count*rand()/RAND_MAX;
194
 
 
195
 
          for(j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++)
196
 
            {
197
 
              if(chose<=(*list)[j].run_count)
198
 
                {
199
 
                  /* Swap j with i */
200
 
                  if(j!=i)
201
 
                    {
202
 
                      struct srventry temp;
203
 
 
204
 
                      memcpy(&temp,&(*list)[j],sizeof(struct srventry));
205
 
                      memcpy(&(*list)[j],&(*list)[i],sizeof(struct srventry));
206
 
                      memcpy(&(*list)[i],&temp,sizeof(struct srventry));
207
 
                    }
208
 
                  break;
209
 
                }
210
 
            }
211
 
        }
 
65
  int srvcount=0;
 
66
  u16 count;
 
67
  int i, rc;
 
68
 
 
69
  *list = NULL;
 
70
 
 
71
#ifdef USE_ADNS
 
72
  {
 
73
    adns_state state;
 
74
    adns_answer *answer = NULL;
 
75
    
 
76
    rc = adns_init (&state, adns_if_noerrprint, NULL);
 
77
    if (rc)
 
78
      {
 
79
        log_error ("error initializing adns: %s\n", strerror (errno));
 
80
        return -1;
 
81
      }
 
82
 
 
83
    rc = adns_synchronous (state, name, adns_r_srv, adns_qf_quoteok_query,
 
84
                           &answer);
 
85
    if (rc)
 
86
      {
 
87
        log_error ("DNS query failed: %s\n", strerror (errno));
 
88
        adns_finish (state);
 
89
        return -1;
 
90
      }
 
91
    if (answer->status != adns_s_ok 
 
92
        || answer->type != adns_r_srv || !answer->nrrs)
 
93
      {
 
94
        /* log_error ("DNS query returned an error or no records: %s (%s)\n", */
 
95
        /*            adns_strerror (answer->status), */
 
96
        /*            adns_errabbrev (answer->status)); */
 
97
        adns_free (answer);
 
98
        adns_finish (state);
 
99
        return 0;
 
100
      }
 
101
 
 
102
    for (count = 0; count < answer->nrrs; count++)
 
103
      {
 
104
        struct srventry *srv = NULL;
 
105
        struct srventry *newlist;
 
106
 
 
107
        if (strlen (answer->rrs.srvha[count].ha.host) >= MAXDNAME)
 
108
          {
 
109
            log_info ("hostname in SRV record too long - skipped\n");
 
110
            continue;
 
111
          }
 
112
      
 
113
        newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry));
 
114
        if (!newlist)
 
115
          goto fail;
 
116
        *list = newlist;
 
117
        memset (&(*list)[srvcount], 0, sizeof(struct srventry));
 
118
        srv = &(*list)[srvcount];
 
119
        srvcount++;
 
120
      
 
121
        srv->priority = answer->rrs.srvha[count].priority;
 
122
        srv->weight   = answer->rrs.srvha[count].weight;
 
123
        srv->port     = answer->rrs.srvha[count].port;
 
124
        strcpy (srv->target, answer->rrs.srvha[count].ha.host);
 
125
      }
 
126
 
 
127
    adns_free (answer);
 
128
    adns_finish (state);
 
129
  }
 
130
#else /*!USE_ADNS*/
 
131
  {
 
132
    unsigned char answer[2048];
 
133
    HEADER *header = (HEADER *)answer;
 
134
    unsigned char *pt, *emsg;
 
135
    int r;
 
136
    u16 dlen;
 
137
    
 
138
    r = res_query (name, C_IN, T_SRV, answer, sizeof answer);
 
139
    if (r < sizeof (HEADER) || r > sizeof answer)
 
140
      return -1;
 
141
    if (header->rcode != NOERROR || !(count=ntohs (header->ancount)))
 
142
      return 0; /* Error or no record found.  */
 
143
    
 
144
    emsg = &answer[r];
 
145
    pt = &answer[sizeof(HEADER)];
 
146
  
 
147
    /* Skip over the query */
 
148
    rc = dn_skipname (pt, emsg);
 
149
    if (rc == -1)
 
150
      goto fail;
 
151
  
 
152
    pt += rc + QFIXEDSZ;
 
153
  
 
154
    while (count-- > 0 && pt < emsg)
 
155
      {
 
156
        struct srventry *srv=NULL;
 
157
        u16 type,class;
 
158
        struct srventry *newlist;
 
159
      
 
160
        newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry));
 
161
        if (!newlist)
 
162
          goto fail;
 
163
        *list = newlist;
 
164
        memset(&(*list)[srvcount],0,sizeof(struct srventry));
 
165
        srv=&(*list)[srvcount];
 
166
        srvcount++;
 
167
      
 
168
        rc = dn_skipname(pt,emsg); /* the name we just queried for */
 
169
        if (rc == -1)
 
170
          goto fail;
 
171
        pt+=rc;
 
172
      
 
173
        /* Truncated message? */
 
174
        if((emsg-pt)<16)
 
175
          goto fail;
 
176
      
 
177
        type=*pt++ << 8;
 
178
        type|=*pt++;
 
179
        /* We asked for SRV and got something else !? */
 
180
        if(type!=T_SRV)
 
181
          goto fail;
 
182
      
 
183
        class=*pt++ << 8;
 
184
        class|=*pt++;
 
185
        /* We asked for IN and got something else !? */
 
186
        if(class!=C_IN)
 
187
          goto fail;
 
188
      
 
189
        pt+=4; /* ttl */
 
190
        dlen=*pt++ << 8;
 
191
        dlen|=*pt++;
 
192
        srv->priority=*pt++ << 8;
 
193
        srv->priority|=*pt++;
 
194
        srv->weight=*pt++ << 8;
 
195
        srv->weight|=*pt++;
 
196
        srv->port=*pt++ << 8;
 
197
        srv->port|=*pt++;
 
198
      
 
199
        /* Get the name.  2782 doesn't allow name compression, but
 
200
           dn_expand still works to pull the name out of the
 
201
           packet. */
 
202
        rc = dn_expand(answer,emsg,pt,srv->target,MAXDNAME);
 
203
        if (rc == 1 && srv->target[0] == 0) /* "." */
 
204
          {
 
205
            xfree(*list);
 
206
            *list = NULL;
 
207
            return 0;
 
208
          }
 
209
        if (rc == -1)
 
210
          goto fail;
 
211
        pt += rc;
 
212
        /* Corrupt packet? */
 
213
        if (dlen != rc+6)
 
214
          goto fail;
 
215
      }
 
216
  }
 
217
#endif /*!USE_ADNS*/
 
218
  
 
219
  /* Now we have an array of all the srv records. */
 
220
  
 
221
  /* Order by priority */
 
222
  qsort(*list,srvcount,sizeof(struct srventry),priosort);
 
223
  
 
224
  /* For each priority, move the zero-weighted items first. */
 
225
  for (i=0; i < srvcount; i++)
 
226
    {
 
227
      int j;
 
228
      
 
229
      for (j=i;j < srvcount && (*list)[i].priority == (*list)[j].priority; j++)
 
230
        {
 
231
          if((*list)[j].weight==0)
 
232
            {
 
233
              /* Swap j with i */
 
234
              if(j!=i)
 
235
                {
 
236
                  struct srventry temp;
 
237
                  
 
238
                  memcpy (&temp,&(*list)[j],sizeof(struct srventry));
 
239
                  memcpy (&(*list)[j],&(*list)[i],sizeof(struct srventry));
 
240
                  memcpy (&(*list)[i],&temp,sizeof(struct srventry));
 
241
                }
 
242
              
 
243
              break;
 
244
            }
 
245
        }
 
246
    }
 
247
 
 
248
  /* Run the RFC-2782 weighting algorithm.  We don't need very high
 
249
     quality randomness for this, so regular libc srand/rand is
 
250
     sufficient.  Fixme: It is a bit questionaly to reinitalize srand
 
251
     - better use a gnupg fucntion for this.  */
 
252
  srand(time(NULL)*getpid());
 
253
 
 
254
  for (i=0; i < srvcount; i++)
 
255
    {
 
256
      int j;
 
257
      float prio_count=0,chose;
 
258
      
 
259
      for (j=i; j < srvcount && (*list)[i].priority == (*list)[j].priority; j++)
 
260
        {
 
261
          prio_count+=(*list)[j].weight;
 
262
          (*list)[j].run_count=prio_count;
 
263
        }
 
264
      
 
265
      chose=prio_count*rand()/RAND_MAX;
 
266
      
 
267
      for (j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++)
 
268
        {
 
269
          if (chose<=(*list)[j].run_count)
 
270
            {
 
271
              /* Swap j with i */
 
272
              if(j!=i)
 
273
                {
 
274
                  struct srventry temp;
 
275
                  
 
276
                  memcpy(&temp,&(*list)[j],sizeof(struct srventry));
 
277
                  memcpy(&(*list)[j],&(*list)[i],sizeof(struct srventry));
 
278
                  memcpy(&(*list)[i],&temp,sizeof(struct srventry));
 
279
                }
 
280
              break;
 
281
            }
 
282
        }
212
283
    }
213
284
  
214
285
  return srvcount;
215
286
 
216
 
 noanswer:
217
 
  xfree(*list);
218
 
  *list=NULL;
219
 
  return 0;
220
 
 
221
287
 fail:
222
288
  xfree(*list);
223
289
  *list=NULL;
250
316
 
251
317
/*
252
318
Local Variables:
253
 
compile-command: "cc -DTEST -I.. -I../include -Wall -g -o srv srv.c -lresolv libutil.a"
 
319
compile-command: "cc -DTEST -I.. -I../include -Wall -g -o srv srv.c -lresolv  ../tools/no-libgcrypt.o  ../jnlib/libjnlib.a"
254
320
End:
255
321
*/