ares_parse_srv_reply.c revision a3b55a024b03321be969a892cb0992bad14266af
943N/A/*
830N/A SSSD
830N/A
919N/A Async resolver - SRV records parsing
919N/A
919N/A Authors:
919N/A Jakub Hrozek <jhrozek@redhat.com>
919N/A
830N/A Copyright (C) Red Hat, Inc 2009
919N/A
919N/A This program is free software; you can redistribute it and/or modify
919N/A it under the terms of the GNU General Public License as published by
830N/A the Free Software Foundation; either version 3 of the License, or
919N/A (at your option) any later version.
919N/A
919N/A This program is distributed in the hope that it will be useful,
919N/A but WITHOUT ANY WARRANTY; without even the implied warranty of
919N/A MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
919N/A GNU General Public License for more details.
919N/A
830N/A You should have received a copy of the GNU General Public License
830N/A along with this program. If not, see <http://www.gnu.org/licenses/>.
830N/A*/
830N/A
830N/A/*
830N/A * This code is based on other c-ares parsing licensed as follows:
830N/A
830N/A * Copyright 1998 by the Massachusetts Institute of Technology.
830N/A *
830N/A * Permission to use, copy, modify, and distribute this
830N/A * software and its documentation for any purpose and without
830N/A * fee is hereby granted, provided that the above copyright
830N/A * notice appear in all copies and that both that copyright
830N/A * notice and this permission notice appear in supporting
830N/A * documentation, and that the name of M.I.T. not be used in
830N/A * advertising or publicity pertaining to distribution of the
830N/A * software without specific, written prior permission.
830N/A * M.I.T. makes no representations about the suitability of
830N/A * this software for any purpose. It is provided "as is"
830N/A * without express or implied warranty.
830N/A */
830N/A
830N/A
830N/A#include <sys/socket.h>
830N/A#include <netinet/in.h>
830N/A#include <arpa/inet.h>
830N/A#include <netdb.h>
830N/A#include <arpa/nameser.h>
830N/A#include <stdlib.h>
830N/A#include <string.h>
830N/A#include "ares.h"
830N/A/* this drags in some private macros c-ares uses */
830N/A#include "ares_dns.h"
830N/A#include "ares_data.h"
830N/A
830N/A#include "ares_parse_srv_reply.h"
830N/A
830N/Aint _ares_parse_srv_reply (const unsigned char *abuf, int alen,
830N/A struct ares_srv_reply **srv_out)
830N/A{
830N/A unsigned int qdcount, ancount, i;
830N/A const unsigned char *aptr, *vptr;
830N/A int status, rr_type, rr_class, rr_len;
830N/A long len;
830N/A char *hostname = NULL, *rr_name = NULL;
830N/A struct ares_srv_reply *srv_head = NULL;
830N/A struct ares_srv_reply *srv_last = NULL;
830N/A struct ares_srv_reply *srv_curr;
830N/A
830N/A /* Set *srv_out to NULL for all failure cases. */
830N/A *srv_out = NULL;
830N/A
830N/A /* Give up if abuf doesn't have room for a header. */
830N/A if (alen < HFIXEDSZ)
830N/A return ARES_EBADRESP;
830N/A
830N/A /* Fetch the question and answer count from the header. */
830N/A qdcount = DNS_HEADER_QDCOUNT (abuf);
830N/A ancount = DNS_HEADER_ANCOUNT (abuf);
830N/A if (qdcount != 1)
830N/A return ARES_EBADRESP;
830N/A if (ancount == 0)
830N/A return ARES_ENODATA;
830N/A
830N/A /* Expand the name from the question, and skip past the question. */
830N/A aptr = abuf + HFIXEDSZ;
830N/A status = ares_expand_name (aptr, abuf, alen, &hostname, &len);
830N/A if (status != ARES_SUCCESS)
830N/A return status;
830N/A
830N/A if (aptr + len + QFIXEDSZ > abuf + alen)
830N/A {
830N/A free (hostname);
830N/A return ARES_EBADRESP;
830N/A }
830N/A aptr += len + QFIXEDSZ;
830N/A
830N/A /* Examine each answer resource record (RR) in turn. */
830N/A for (i = 0; i < (int) ancount; i++)
830N/A {
830N/A /* Decode the RR up to the data field. */
830N/A status = ares_expand_name (aptr, abuf, alen, &rr_name, &len);
830N/A if (status != ARES_SUCCESS)
830N/A {
830N/A break;
830N/A }
830N/A aptr += len;
830N/A if (aptr + RRFIXEDSZ > abuf + alen)
830N/A {
830N/A status = ARES_EBADRESP;
830N/A break;
830N/A }
830N/A rr_type = DNS_RR_TYPE (aptr);
830N/A rr_class = DNS_RR_CLASS (aptr);
830N/A rr_len = DNS_RR_LEN (aptr);
830N/A aptr += RRFIXEDSZ;
830N/A
830N/A /* Check if we are really looking at a SRV record */
830N/A if (rr_class == C_IN && rr_type == T_SRV)
830N/A {
830N/A /* parse the SRV record itself */
830N/A if (rr_len < 6)
830N/A {
830N/A status = ARES_EBADRESP;
830N/A break;
830N/A }
830N/A
830N/A /* Allocate storage for this SRV answer appending it to the list */
830N/A srv_curr = _ares_malloc_data(ARES_DATATYPE_SRV_REPLY);
830N/A if (!srv_curr)
830N/A {
830N/A status = ARES_ENOMEM;
830N/A break;
830N/A }
830N/A if (srv_last)
830N/A {
830N/A srv_last->next = srv_curr;
830N/A }
830N/A else
830N/A {
830N/A srv_head = srv_curr;
830N/A }
830N/A srv_last = srv_curr;
830N/A
830N/A vptr = aptr;
830N/A srv_curr->priority = ntohs (*((const unsigned short *)vptr));
830N/A vptr += sizeof(const unsigned short);
830N/A srv_curr->weight = ntohs (*((const unsigned short *)vptr));
830N/A vptr += sizeof(const unsigned short);
830N/A srv_curr->port = ntohs (*((const unsigned short *)vptr));
830N/A vptr += sizeof(const unsigned short);
830N/A
830N/A status = ares_expand_name (vptr, abuf, alen, &srv_curr->host, &len);
830N/A if (status != ARES_SUCCESS)
830N/A break;
830N/A }
830N/A
830N/A /* Don't lose memory in the next iteration */
830N/A free(rr_name);
830N/A rr_name = NULL;
830N/A
830N/A /* Move on to the next record */
830N/A aptr += rr_len;
830N/A }
830N/A
830N/A if (hostname)
830N/A free (hostname);
830N/A if (rr_name)
830N/A free (rr_name);
830N/A
830N/A /* clean up on error */
830N/A if (status != ARES_SUCCESS)
830N/A {
830N/A if (srv_head)
830N/A _ares_free_data (srv_head);
830N/A return status;
830N/A }
830N/A
830N/A /* everything looks fine, return the data */
830N/A *srv_out = srv_head;
830N/A
830N/A return ARES_SUCCESS;
830N/A}
830N/A