root/net/dns_resolver/dns_query.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dns_query

   1 /* Upcall routine, designed to work as a key type and working through
   2  * /sbin/request-key to contact userspace when handling DNS queries.
   3  *
   4  * See Documentation/networking/dns_resolver.txt
   5  *
   6  *   Copyright (c) 2007 Igor Mammedov
   7  *   Author(s): Igor Mammedov (niallain@gmail.com)
   8  *              Steve French (sfrench@us.ibm.com)
   9  *              Wang Lei (wang840925@gmail.com)
  10  *              David Howells (dhowells@redhat.com)
  11  *
  12  *   The upcall wrapper used to make an arbitrary DNS query.
  13  *
  14  *   This function requires the appropriate userspace tool dns.upcall to be
  15  *   installed and something like the following lines should be added to the
  16  *   /etc/request-key.conf file:
  17  *
  18  *      create dns_resolver * * /sbin/dns.upcall %k
  19  *
  20  *   For example to use this module to query AFSDB RR:
  21  *
  22  *      create dns_resolver afsdb:* * /sbin/dns.afsdb %k
  23  *
  24  *   This library is free software; you can redistribute it and/or modify
  25  *   it under the terms of the GNU Lesser General Public License as published
  26  *   by the Free Software Foundation; either version 2.1 of the License, or
  27  *   (at your option) any later version.
  28  *
  29  *   This library is distributed in the hope that it will be useful,
  30  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  31  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
  32  *   the GNU Lesser General Public License for more details.
  33  *
  34  *   You should have received a copy of the GNU Lesser General Public License
  35  *   along with this library; if not, see <http://www.gnu.org/licenses/>.
  36  */
  37 
  38 #include <linux/module.h>
  39 #include <linux/slab.h>
  40 #include <linux/cred.h>
  41 #include <linux/dns_resolver.h>
  42 #include <linux/err.h>
  43 #include <net/net_namespace.h>
  44 
  45 #include <keys/dns_resolver-type.h>
  46 #include <keys/user-type.h>
  47 
  48 #include "internal.h"
  49 
  50 /**
  51  * dns_query - Query the DNS
  52  * @net: The network namespace to operate in.
  53  * @type: Query type (or NULL for straight host->IP lookup)
  54  * @name: Name to look up
  55  * @namelen: Length of name
  56  * @options: Request options (or NULL if no options)
  57  * @_result: Where to place the returned data (or NULL)
  58  * @_expiry: Where to store the result expiry time (or NULL)
  59  * @invalidate: Always invalidate the key after use
  60  *
  61  * The data will be returned in the pointer at *result, if provided, and the
  62  * caller is responsible for freeing it.
  63  *
  64  * The description should be of the form "[<query_type>:]<domain_name>", and
  65  * the options need to be appropriate for the query type requested.  If no
  66  * query_type is given, then the query is a straight hostname to IP address
  67  * lookup.
  68  *
  69  * The DNS resolution lookup is performed by upcalling to userspace by way of
  70  * requesting a key of type dns_resolver.
  71  *
  72  * Returns the size of the result on success, -ve error code otherwise.
  73  */
  74 int dns_query(struct net *net,
  75               const char *type, const char *name, size_t namelen,
  76               const char *options, char **_result, time64_t *_expiry,
  77               bool invalidate)
  78 {
  79         struct key *rkey;
  80         struct user_key_payload *upayload;
  81         const struct cred *saved_cred;
  82         size_t typelen, desclen;
  83         char *desc, *cp;
  84         int ret, len;
  85 
  86         kenter("%s,%*.*s,%zu,%s",
  87                type, (int)namelen, (int)namelen, name, namelen, options);
  88 
  89         if (!name || namelen == 0)
  90                 return -EINVAL;
  91 
  92         /* construct the query key description as "[<type>:]<name>" */
  93         typelen = 0;
  94         desclen = 0;
  95         if (type) {
  96                 typelen = strlen(type);
  97                 if (typelen < 1)
  98                         return -EINVAL;
  99                 desclen += typelen + 1;
 100         }
 101 
 102         if (namelen < 3 || namelen > 255)
 103                 return -EINVAL;
 104         desclen += namelen + 1;
 105 
 106         desc = kmalloc(desclen, GFP_KERNEL);
 107         if (!desc)
 108                 return -ENOMEM;
 109 
 110         cp = desc;
 111         if (type) {
 112                 memcpy(cp, type, typelen);
 113                 cp += typelen;
 114                 *cp++ = ':';
 115         }
 116         memcpy(cp, name, namelen);
 117         cp += namelen;
 118         *cp = '\0';
 119 
 120         if (!options)
 121                 options = "";
 122         kdebug("call request_key(,%s,%s)", desc, options);
 123 
 124         /* make the upcall, using special credentials to prevent the use of
 125          * add_key() to preinstall malicious redirections
 126          */
 127         saved_cred = override_creds(dns_resolver_cache);
 128         rkey = request_key_net(&key_type_dns_resolver, desc, net, options);
 129         revert_creds(saved_cred);
 130         kfree(desc);
 131         if (IS_ERR(rkey)) {
 132                 ret = PTR_ERR(rkey);
 133                 goto out;
 134         }
 135 
 136         down_read(&rkey->sem);
 137         set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags);
 138         rkey->perm |= KEY_USR_VIEW;
 139 
 140         ret = key_validate(rkey);
 141         if (ret < 0)
 142                 goto put;
 143 
 144         /* If the DNS server gave an error, return that to the caller */
 145         ret = PTR_ERR(rkey->payload.data[dns_key_error]);
 146         if (ret)
 147                 goto put;
 148 
 149         upayload = user_key_payload_locked(rkey);
 150         len = upayload->datalen;
 151 
 152         if (_result) {
 153                 ret = -ENOMEM;
 154                 *_result = kmemdup_nul(upayload->data, len, GFP_KERNEL);
 155                 if (!*_result)
 156                         goto put;
 157         }
 158 
 159         if (_expiry)
 160                 *_expiry = rkey->expiry;
 161 
 162         ret = len;
 163 put:
 164         up_read(&rkey->sem);
 165         if (invalidate)
 166                 key_invalidate(rkey);
 167         key_put(rkey);
 168 out:
 169         kleave(" = %d", ret);
 170         return ret;
 171 }
 172 EXPORT_SYMBOL(dns_query);

/* [<][>][^][v][top][bottom][index][help] */