From e6918187568dbd01842d8d1d2c808ce16a894239 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 21 Apr 2024 13:54:28 +0200 Subject: Adding upstream version 18.2.2. Signed-off-by: Daniel Baumann --- src/c-ares/ares_parse_srv_reply.c | 179 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 src/c-ares/ares_parse_srv_reply.c (limited to 'src/c-ares/ares_parse_srv_reply.c') diff --git a/src/c-ares/ares_parse_srv_reply.c b/src/c-ares/ares_parse_srv_reply.c new file mode 100644 index 000000000..824ff3aed --- /dev/null +++ b/src/c-ares/ares_parse_srv_reply.c @@ -0,0 +1,179 @@ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * Copyright (C) 2009 by Jakub Hrozek + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#include "ares.h" +#include "ares_dns.h" +#include "ares_data.h" +#include "ares_private.h" + +/* AIX portability check */ +#ifndef T_SRV +# define T_SRV 33 /* server selection */ +#endif + +int +ares_parse_srv_reply (const unsigned char *abuf, int alen, + struct ares_srv_reply **srv_out) +{ + unsigned int qdcount, ancount, i; + const unsigned char *aptr, *vptr; + int status, rr_type, rr_class, rr_len; + long len; + char *hostname = NULL, *rr_name = NULL; + struct ares_srv_reply *srv_head = NULL; + struct ares_srv_reply *srv_last = NULL; + struct ares_srv_reply *srv_curr; + + /* Set *srv_out to NULL for all failure cases. */ + *srv_out = NULL; + + /* Give up if abuf doesn't have room for a header. */ + if (alen < HFIXEDSZ) + return ARES_EBADRESP; + + /* Fetch the question and answer count from the header. */ + qdcount = DNS_HEADER_QDCOUNT (abuf); + ancount = DNS_HEADER_ANCOUNT (abuf); + if (qdcount != 1) + return ARES_EBADRESP; + if (ancount == 0) + return ARES_ENODATA; + + /* Expand the name from the question, and skip past the question. */ + aptr = abuf + HFIXEDSZ; + status = ares_expand_name (aptr, abuf, alen, &hostname, &len); + if (status != ARES_SUCCESS) + return status; + + if (aptr + len + QFIXEDSZ > abuf + alen) + { + ares_free (hostname); + return ARES_EBADRESP; + } + aptr += len + QFIXEDSZ; + + /* Examine each answer resource record (RR) in turn. */ + for (i = 0; i < ancount; i++) + { + /* Decode the RR up to the data field. */ + status = ares_expand_name (aptr, abuf, alen, &rr_name, &len); + if (status != ARES_SUCCESS) + { + break; + } + aptr += len; + if (aptr + RRFIXEDSZ > abuf + alen) + { + status = ARES_EBADRESP; + break; + } + rr_type = DNS_RR_TYPE (aptr); + rr_class = DNS_RR_CLASS (aptr); + rr_len = DNS_RR_LEN (aptr); + aptr += RRFIXEDSZ; + if (aptr + rr_len > abuf + alen) + { + status = ARES_EBADRESP; + break; + } + + /* Check if we are really looking at a SRV record */ + if (rr_class == C_IN && rr_type == T_SRV) + { + /* parse the SRV record itself */ + if (rr_len < 6) + { + status = ARES_EBADRESP; + break; + } + + /* Allocate storage for this SRV answer appending it to the list */ + srv_curr = ares_malloc_data(ARES_DATATYPE_SRV_REPLY); + if (!srv_curr) + { + status = ARES_ENOMEM; + break; + } + if (srv_last) + { + srv_last->next = srv_curr; + } + else + { + srv_head = srv_curr; + } + srv_last = srv_curr; + + vptr = aptr; + srv_curr->priority = DNS__16BIT(vptr); + vptr += sizeof(unsigned short); + srv_curr->weight = DNS__16BIT(vptr); + vptr += sizeof(unsigned short); + srv_curr->port = DNS__16BIT(vptr); + vptr += sizeof(unsigned short); + + status = ares_expand_name (vptr, abuf, alen, &srv_curr->host, &len); + if (status != ARES_SUCCESS) + break; + } + + /* Don't lose memory in the next iteration */ + ares_free (rr_name); + rr_name = NULL; + + /* Move on to the next record */ + aptr += rr_len; + } + + if (hostname) + ares_free (hostname); + if (rr_name) + ares_free (rr_name); + + /* clean up on error */ + if (status != ARES_SUCCESS) + { + if (srv_head) + ares_free_data (srv_head); + return status; + } + + /* everything looks fine, return the data */ + *srv_out = srv_head; + + return ARES_SUCCESS; +} -- cgit v1.2.3