~ubuntu-branches/ubuntu/saucy/sssd/saucy

« back to all changes in this revision

Viewing changes to src/resolv/ares/ares_parse_srv_reply.c

  • Committer: Stéphane Graber
  • Date: 2011-06-15 16:23:14 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: stgraber@ubuntu.com-20110615162314-rbhoppnpaxfqo5q7
Merge 1.5.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   SSSD
 
3
 
 
4
   Async resolver - SRV records parsing
 
5
 
 
6
   Authors:
 
7
        Jakub Hrozek <jhrozek@redhat.com>
 
8
 
 
9
   Copyright (C) Red Hat, Inc 2009
 
10
 
 
11
   This program is free software; you can redistribute it and/or modify
 
12
   it under the terms of the GNU General Public License as published by
 
13
   the Free Software Foundation; either version 3 of the License, or
 
14
   (at your option) any later version.
 
15
 
 
16
   This program is distributed in the hope that it will be useful,
 
17
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
19
   GNU General Public License for more details.
 
20
 
 
21
   You should have received a copy of the GNU General Public License
 
22
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
23
*/
 
24
 
 
25
/*
 
26
 * This code is based on other c-ares parsing licensed as follows:
 
27
 
 
28
 * Copyright 1998 by the Massachusetts Institute of Technology.
 
29
 *
 
30
 * Permission to use, copy, modify, and distribute this
 
31
 * software and its documentation for any purpose and without
 
32
 * fee is hereby granted, provided that the above copyright
 
33
 * notice appear in all copies and that both that copyright
 
34
 * notice and this permission notice appear in supporting
 
35
 * documentation, and that the name of M.I.T. not be used in
 
36
 * advertising or publicity pertaining to distribution of the
 
37
 * software without specific, written prior permission.
 
38
 * M.I.T. makes no representations about the suitability of
 
39
 * this software for any purpose.  It is provided "as is"
 
40
 * without express or implied warranty.
 
41
 */
 
42
 
 
43
 
 
44
#include <sys/socket.h>
 
45
#include <netinet/in.h>
 
46
#include <arpa/inet.h>
 
47
#include <netdb.h>
 
48
#include <arpa/nameser.h>
 
49
#include <stdlib.h>
 
50
#include <string.h>
 
51
#include "ares.h"
 
52
/* this drags in some private macros c-ares uses */
 
53
#include "ares_dns.h"
 
54
#include "ares_data.h"
 
55
 
 
56
#include "ares_parse_srv_reply.h"
 
57
 
 
58
int _ares_parse_srv_reply (const unsigned char *abuf, int alen,
 
59
                           struct ares_srv_reply **srv_out)
 
60
{
 
61
  unsigned int qdcount, ancount, i;
 
62
  const unsigned char *aptr, *vptr;
 
63
  int status, rr_type, rr_class, rr_len;
 
64
  long len;
 
65
  char *hostname = NULL, *rr_name = NULL;
 
66
  struct ares_srv_reply *srv_head = NULL;
 
67
  struct ares_srv_reply *srv_last = NULL;
 
68
  struct ares_srv_reply *srv_curr;
 
69
 
 
70
  /* Set *srv_out to NULL for all failure cases. */
 
71
  *srv_out = NULL;
 
72
 
 
73
  /* Give up if abuf doesn't have room for a header. */
 
74
  if (alen < HFIXEDSZ)
 
75
    return ARES_EBADRESP;
 
76
 
 
77
  /* Fetch the question and answer count from the header. */
 
78
  qdcount = DNS_HEADER_QDCOUNT (abuf);
 
79
  ancount = DNS_HEADER_ANCOUNT (abuf);
 
80
  if (qdcount != 1)
 
81
    return ARES_EBADRESP;
 
82
  if (ancount == 0)
 
83
    return ARES_ENODATA;
 
84
 
 
85
  /* Expand the name from the question, and skip past the question. */
 
86
  aptr = abuf + HFIXEDSZ;
 
87
  status = ares_expand_name (aptr, abuf, alen, &hostname, &len);
 
88
  if (status != ARES_SUCCESS)
 
89
    return status;
 
90
 
 
91
  if (aptr + len + QFIXEDSZ > abuf + alen)
 
92
    {
 
93
      free (hostname);
 
94
      return ARES_EBADRESP;
 
95
    }
 
96
  aptr += len + QFIXEDSZ;
 
97
 
 
98
  /* Examine each answer resource record (RR) in turn. */
 
99
  for (i = 0; i < (int) ancount; i++)
 
100
    {
 
101
      /* Decode the RR up to the data field. */
 
102
      status = ares_expand_name (aptr, abuf, alen, &rr_name, &len);
 
103
      if (status != ARES_SUCCESS)
 
104
        {
 
105
          break;
 
106
        }
 
107
      aptr += len;
 
108
      if (aptr + RRFIXEDSZ > abuf + alen)
 
109
        {
 
110
          status = ARES_EBADRESP;
 
111
          break;
 
112
        }
 
113
      rr_type = DNS_RR_TYPE (aptr);
 
114
      rr_class = DNS_RR_CLASS (aptr);
 
115
      rr_len = DNS_RR_LEN (aptr);
 
116
      aptr += RRFIXEDSZ;
 
117
 
 
118
      /* Check if we are really looking at a SRV record */
 
119
      if (rr_class == C_IN && rr_type == T_SRV)
 
120
        {
 
121
          /* parse the SRV record itself */
 
122
          if (rr_len < 6)
 
123
            {
 
124
              status = ARES_EBADRESP;
 
125
              break;
 
126
            }
 
127
 
 
128
          /* Allocate storage for this SRV answer appending it to the list */
 
129
          srv_curr = _ares_malloc_data(ARES_DATATYPE_SRV_REPLY);
 
130
          if (!srv_curr)
 
131
            {
 
132
              status = ARES_ENOMEM;
 
133
              break;
 
134
            }
 
135
          if (srv_last)
 
136
            {
 
137
              srv_last->next = srv_curr;
 
138
            }
 
139
          else
 
140
            {
 
141
              srv_head = srv_curr;
 
142
            }
 
143
          srv_last = srv_curr;
 
144
 
 
145
          vptr = aptr;
 
146
          srv_curr->priority = DNS__16BIT(vptr);
 
147
          vptr += sizeof(const unsigned short);
 
148
          srv_curr->weight = DNS__16BIT(vptr);
 
149
          vptr += sizeof(const unsigned short);
 
150
          srv_curr->port = DNS__16BIT(vptr);
 
151
          vptr += sizeof(const unsigned short);
 
152
 
 
153
          status = ares_expand_name (vptr, abuf, alen, &srv_curr->host, &len);
 
154
          if (status != ARES_SUCCESS)
 
155
            break;
 
156
        }
 
157
 
 
158
      /* Don't lose memory in the next iteration */
 
159
      free(rr_name);
 
160
      rr_name = NULL;
 
161
 
 
162
      /* Move on to the next record */
 
163
      aptr += rr_len;
 
164
    }
 
165
 
 
166
  if (hostname)
 
167
    free (hostname);
 
168
  if (rr_name)
 
169
    free (rr_name);
 
170
 
 
171
  /* clean up on error */
 
172
  if (status != ARES_SUCCESS)
 
173
    {
 
174
      if (srv_head)
 
175
        _ares_free_data (srv_head);
 
176
      return status;
 
177
    }
 
178
 
 
179
  /* everything looks fine, return the data */
 
180
  *srv_out = srv_head;
 
181
 
 
182
  return ARES_SUCCESS;
 
183
}