@@ -29,6 +29,8 @@
extern int request_dns_resolution(const char *description, const char *options,
char **result);
extern int dns_resolve_unc_to_ip(const char *unc, char **ip_addr);
+extern int dns_query(const char *type, const char *name, const char *inetf,
+ char **_result, time_t *_expiry);
#endif /* KERNEL */
@@ -4,4 +4,4 @@
obj-$(CONFIG_DNS_RESOLVER) += dnsresolver.o
-dnsresolver-objs := dns_resolver.o resolv_unc_to_ip.o
+dnsresolver-objs := dns_resolver.o resolv_unc_to_ip.o dns_query.o
new file mode 100644
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2010 Wang Lei
+ * Author(s): Wang Lei (wang840925@gmail.com)
+ * David Howells <dhowells@redhat.com>
+ *
+ * The upcall wrapper used to make an arbitrary DNS query.
+ *
+ * This function requires the appropriate userspace tool dns.upcall to be
+ * installed and something like the following lines should be added to the
+ * /etc/request-key.conf file:
+ *
+ * create dns_resolver * * /sbin/dns.upcall %k
+ *
+ * For example to use this module to query AFSDB RR:
+ *
+ * create dns_resolver afsdb:* * /sbin/dns.afsdb %k
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/dns_resolver.h>
+#include <keys/dnsresolver-type.h>
+#include <keys/user-type.h>
+
+#include "internal.h"
+
+/**
+ * dns_query - Query DNS
+ * @type: Query type
+ * @name: Name to look up
+ * @options: Space-separated options appropriate to the query type
+ * @_result: Where to return the result
+ * @_expiry: Where to store the result expiry time (or NULL)
+ *
+ * The result is copied into a buffer and returned in *_result. The caller is
+ * responsible for freeing this buffer. The result is NUL-terminated, though
+ * the termination is not included in the result size. Optionally, the time at
+ * which the result expires is stored in *_expiry.
+ *
+ * Note that the upcall program may have edited the result from what the DNS
+ * server returned, for example to turn hostnames obtained by the lookup into
+ * IP addresses for the AFSDB query type.
+ *
+ * The options may include such things as IP address family ("ipv4" or "ipv6")
+ *
+ * Returns the size of the result on success, -ve error code otherwise.
+ */
+int dns_query(const char *type, const char *name, const char *options,
+ char **_result, time_t *_expiry)
+{
+ struct key *rkey;
+ size_t typelen, namelen;
+ struct user_key_payload *upayload;
+ char *desc;
+ int ret, len;
+
+ kenter("%s,%s,%s,,,", type, name, options);
+
+ ret = -EINVAL;
+ if (!type || !name || !_result)
+ goto err;
+
+ typelen = strlen(type);
+ namelen = strlen(name);
+ if (typelen < 1 || namelen < 3)
+ goto err;
+
+ ret = -ENOMEM;
+ /* construct the query key description as "<type>:<name>" */
+ desc = kmalloc(typelen + 1 + namelen + 1, GFP_KERNEL);
+ if (!desc)
+ goto err;
+
+ memcpy(desc, type, typelen);
+ desc[typelen] = ':';
+ memcpy(desc + typelen + 1, name, namelen + 1);
+
+ if (!options)
+ options = "";
+ kdebug("call request_key(,%s,%s)", desc, options);
+
+ /* make the upcall */
+ rkey = request_key(&key_type_dns_resolver, desc, options);
+ kfree(desc);
+
+ if (IS_ERR(rkey)) {
+ ret = PTR_ERR(rkey);
+ goto err;
+ }
+
+ down_read(&rkey->sem);
+
+ upayload = rcu_dereference_check(rkey->payload.data,
+ lockdep_is_held(&rkey->sem));
+ len = upayload->datalen;
+ *_result = kmalloc(len + 1, GFP_KERNEL);
+ if (!*_result) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memcpy(*_result, upayload->data, len + 1);
+ if (_expiry)
+ *_expiry = rkey->expiry;
+ ret = len;
+
+
+out:
+ up_read(&rkey->sem);
+ key_put(rkey);
+
+err:
+ kleave(" = %d [r=%s]", ret, *_result);
+ return ret;
+}
+EXPORT_SYMBOL(dns_query);