From: Wang Lei <[email protected]>

When the dns_resolver upcall program packages results and instantiates its key
with them, the offered data may have a number of options appended to it.  Each
option is of the form:

        #key=value

This implements an option by which the key's expiry time can be set from the
DNS TTL datum:

        #expiry=<nnn>

where <nnn> is a time_t value.

Signed-off-by: Wang Lei <[email protected]>
Signed-off-by: David Howells <[email protected]>
---

 net/dns_resolver/dns_key.c |   85 ++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 78 insertions(+), 7 deletions(-)

diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c
index 1b1b411..02c7336 100644
--- a/net/dns_resolver/dns_key.c
+++ b/net/dns_resolver/dns_key.c
@@ -42,6 +42,8 @@ MODULE_PARM_DESC(debug, "DNS Resolver debugging mask");
 
 const struct cred *dns_resolver_cache;
 
+#define        DNS_EXPIRY_OPTION       "expiry_time"
+
 /*
  * Instantiate a user defined key for dns_resolver.
  *
@@ -50,17 +52,26 @@ const struct cred *dns_resolver_cache;
  *
  * If the data contains a '#' characters, then we take the clause after each
  * one to be an option of the form 'key=value'.  The actual data of interest is
- * the string leading up to the first '#'.  For instance:
+ * the string leading up to the first '#'.
+ *
+ * The only option currently supported is the expiry time of the key, which can
+ * be set from the TTL field of the DNS record.  The value should be a time_t
+ * time.
+ *
+ * For instance:
+ *
+ *        "ip1,ip2,...#expiry_time=123"
  *
- *        "ip1,ip2,...#foo=bar"
+ * the expiry time of the data is 123 and the data starts after '#'.
  */
 static int
 dns_resolver_instantiate(struct key *key, const void *_data, size_t datalen)
 {
        struct user_key_payload *upayload;
+       unsigned long expiry = 0;
        int ret;
        size_t result_len = 0;
-       const char *data = _data, *opt;
+       const char *data = _data, *end, *opt;
 
        kenter("%%%d,%s,'%s',%zu",
               key->serial, key->description, data, datalen);
@@ -70,13 +81,65 @@ dns_resolver_instantiate(struct key *key, const void 
*_data, size_t datalen)
        datalen--;
 
        /* deal with any options embedded in the data */
-       opt = memchr(data, '#', datalen);
+       end = data + datalen - 1;
+       opt = memchr(data, '#', datalen - 1);
        if (!opt) {
-               kdebug("no options currently supported");
-               return -EINVAL;
+               /* no options: the entire data is the result */
+               kdebug("no options");
+               result_len = datalen - 1;
+       } else {
+               result_len = opt - data;
+               opt++;
+               kdebug("options: '%s'", opt);
+               do {
+                       const char *next_opt, *eq;
+                       int opt_len, opt_nlen, opt_vlen, tmp;
+
+                       next_opt = memchr(opt, '#', end - opt) ?: end;
+                       opt_len = next_opt - opt;
+                       if (!opt_len) {
+                               printk(KERN_WARNING
+                                      "Empty option to dnsresolver key %d\n",
+                                      key->serial);
+                               return -EINVAL;
+                       }
+
+                       eq = memchr(opt, '=', opt_len) ?: end;
+                       opt_nlen = eq - opt;
+                       eq++;
+                       opt_vlen = next_opt - eq; /* will be -1 if no value */
+
+                       tmp = opt_vlen >= 0 ? opt_vlen : 0;
+                       kdebug("option '%*.*s' val '%*.*s'",
+                              opt_nlen, opt_nlen, opt, tmp, tmp, eq);
+
+                       /* see if it's the expiry time */
+                       if (opt_nlen == sizeof(DNS_EXPIRY_OPTION) - 1 &&
+                           memcmp(opt, DNS_EXPIRY_OPTION, opt_nlen) == 0) {
+                               kdebug("expiry time option");
+                               if (opt_vlen <= 0)
+                                       goto bad_option_value;
+
+                               ret = strict_strtoul(eq, 10, &expiry);
+                               if (ret < 0)
+                                       goto bad_option_value;
+                               kdebug("expiry time = %lu", expiry);
+                               goto next_option;
+                       }
+
+               bad_option_value:
+                       printk(KERN_WARNING
+                              "Option '%*.*s' to dnsresolver key %d:"
+                              " bad/missing value\n",
+                              opt_nlen, opt_nlen, opt, key->serial);
+                       return -EINVAL;
+
+               next_option:
+                       opt = next_opt + 1;
+               } while (opt < end);
        }
 
-       result_len = datalen;
+       kdebug("store result");
        ret = key_payload_reserve(key, result_len);
        if (ret < 0)
                return -EINVAL;
@@ -87,11 +150,19 @@ dns_resolver_instantiate(struct key *key, const void 
*_data, size_t datalen)
                return -ENOMEM;
        }
 
+       /* attach the data */
        upayload->datalen = result_len;
        memcpy(upayload->data, data, result_len);
        upayload->data[result_len] = '\0';
        rcu_assign_pointer(key->payload.data, upayload);
 
+       /* if we were given an expiry time, then try to apply it */
+       kdebug("expiry %lu [%lu]", expiry, key->expiry);
+       if (expiry && (key->expiry == 0 || expiry < key->expiry)) {
+               kdebug("set expiry to %ld hence", expiry - get_seconds());
+               key->expiry = expiry;
+       }
+
        kleave(" = 0");
        return 0;
 }

--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to