History

dns: Allow the dns resolver to retrieve a server set

Allow the DNS resolver to retrieve a set of servers and their associated addresses, ports, preference and weight ratings. In terms of communication with userspace, "srv=1" is added to the callout string (the '1' indicating the maximum data version supported by the kernel) to ask the userspace side for this. If the userspace side doesn't recognise it, it will ignore the option and return the usual text address list. If the userspace side does recognise it, it will return some binary data that begins with a zero byte that would cause the string parsers to give an error. The second byte contains the version of the data in the blob (this may be between 1 and the version specified in the callout data). The remainder of the payload is version-specific. In version 1, the payload looks like (note that this is packed): u8 Non-string marker (ie. 0) u8 Content (0 => Server list) u8 Version (ie. 1) u8 Source (eg. DNS_RECORD_FROM_DNS_SRV) u8 Status (eg. DNS_LOOKUP_GOOD) u8 Number of servers foreach-server { u16 Name length (LE) u16 Priority (as per SRV record) (LE) u16 Weight (as per SRV record) (LE) u16 Port (LE) u8 Source (eg. DNS_RECORD_FROM_NSS) u8 Status (eg. DNS_LOOKUP_GOT_NOT_FOUND) u8 Protocol (eg. DNS_SERVER_PROTOCOL_UDP) u8 Number of addresses char[] Name (not NUL-terminated) foreach-address { u8 Family (AF_INET{,6}) union { u8[4] ipv4_addr u8[16] ipv6_addr } } } This can then be used to fetch a whole cell's VL-server configuration for AFS, for example.

David Howells committed 8 years ago

Commit bbb4c431 parent 0aa63eb4 files · +182 −10Browse files

Unified · Split

4 files
  1. include/linux/dns_resolver.h +1 −3
  2. include/uapi/linux/dns_resolver.h +116 −0
  3. net/dns_resolver/dns_key.c +64 −3
  4. net/dns_resolver/dns_query.c +1 −4
include/linux/dns_resolver.h+1−3
@@ -24,11 +24,9 @@ · 23 unmodified lines
24#ifndef _LINUX_DNS_RESOLVER_H24#ifndef _LINUX_DNS_RESOLVER_H
25#define _LINUX_DNS_RESOLVER_H25#define _LINUX_DNS_RESOLVER_H
26 26
27#ifdef __KERNEL__27#include <uapi/linux/dns_resolver.h>
28 28
29extern int dns_query(const char *type, const char *name, size_t namelen,29extern int dns_query(const char *type, const char *name, size_t namelen,
30 const char *options, char **_result, time64_t *_expiry);30 const char *options, char **_result, time64_t *_expiry);
31 31
32#endif /* KERNEL */
33
34#endif /* _LINUX_DNS_RESOLVER_H */32#endif /* _LINUX_DNS_RESOLVER_H */
include/uapi/linux/dns_resolver.h+116−0
@@ -0,0 +1,116 @@
1/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
2/* DNS resolver interface definitions.
3 *
4 * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public Licence
9 * as published by the Free Software Foundation; either version
10 * 2 of the Licence, or (at your option) any later version.
11 */
12
13#ifndef _UAPI_LINUX_DNS_RESOLVER_H
14#define _UAPI_LINUX_DNS_RESOLVER_H
15
16#include <linux/types.h>
17
18/*
19 * Type of payload.
20 */
21enum dns_payload_content_type {
22 DNS_PAYLOAD_IS_SERVER_LIST = 0, /* List of servers, requested by srv=1 */
23};
24
25/*
26 * Type of address that might be found in an address record.
27 */
28enum dns_payload_address_type {
29 DNS_ADDRESS_IS_IPV4 = 0, /* 4-byte AF_INET address */
30 DNS_ADDRESS_IS_IPV6 = 1, /* 16-byte AF_INET6 address */
31};
32
33/*
34 * Type of protocol used to access a server.
35 */
36enum dns_payload_protocol_type {
37 DNS_SERVER_PROTOCOL_UNSPECIFIED = 0,
38 DNS_SERVER_PROTOCOL_UDP = 1, /* Use UDP to talk to the server */
39 DNS_SERVER_PROTOCOL_TCP = 2, /* Use TCP to talk to the server */
40};
41
42/*
43 * Source of record included in DNS resolver payload.
44 */
45enum dns_record_source {
46 DNS_RECORD_UNAVAILABLE = 0, /* No source available (empty record) */
47 DNS_RECORD_FROM_CONFIG = 1, /* From local configuration data */
48 DNS_RECORD_FROM_DNS_A = 2, /* From DNS A or AAAA record */
49 DNS_RECORD_FROM_DNS_AFSDB = 3, /* From DNS AFSDB record */
50 DNS_RECORD_FROM_DNS_SRV = 4, /* From DNS SRV record */
51 DNS_RECORD_FROM_NSS = 5, /* From NSS */
52 NR__dns_record_source
53};
54
55/*
56 * Status of record included in DNS resolver payload.
57 */
58enum dns_lookup_status {
59 DNS_LOOKUP_NOT_DONE = 0, /* No lookup has been made */
60 DNS_LOOKUP_GOOD = 1, /* Good records obtained */
61 DNS_LOOKUP_GOOD_WITH_BAD = 2, /* Good records, some decoding errors */
62 DNS_LOOKUP_BAD = 3, /* Couldn't decode results */
63 DNS_LOOKUP_GOT_NOT_FOUND = 4, /* Got a "Not Found" result */
64 DNS_LOOKUP_GOT_LOCAL_FAILURE = 5, /* Local failure during lookup */
65 DNS_LOOKUP_GOT_TEMP_FAILURE = 6, /* Temporary failure during lookup */
66 DNS_LOOKUP_GOT_NS_FAILURE = 7, /* Name server failure */
67 NR__dns_lookup_status
68};
69
70/*
71 * Header at the beginning of binary format payload.
72 */
73struct dns_payload_header {
74 __u8 zero; /* Zero byte: marks this as not being text */
75 __u8 content; /* enum dns_payload_content_type */
76 __u8 version; /* Encoding version */
77} __packed;
78
79/*
80 * Header at the beginning of a V1 server list. This is followed directly by
81 * the server records. Each server records begins with a struct of type
82 * dns_server_list_v1_server.
83 */
84struct dns_server_list_v1_header {
85 struct dns_payload_header hdr;
86 __u8 source; /* enum dns_record_source */
87 __u8 status; /* enum dns_lookup_status */
88 __u8 nr_servers; /* Number of server records following this */
89} __packed;
90
91/*
92 * Header at the beginning of each V1 server record. This is followed by the
93 * characters of the name with no NUL-terminator, followed by the address
94 * records for that server. Each address record begins with a struct of type
95 * struct dns_server_list_v1_address.
96 */
97struct dns_server_list_v1_server {
98 __u16 name_len; /* Length of name (LE) */
99 __u16 priority; /* Priority (as SRV record) (LE) */
100 __u16 weight; /* Weight (as SRV record) (LE) */
101 __u16 port; /* UDP/TCP port number (LE) */
102 __u8 source; /* enum dns_record_source */
103 __u8 status; /* enum dns_lookup_status */
104 __u8 protocol; /* enum dns_payload_protocol_type */
105 __u8 nr_addrs;
106} __packed;
107
108/*
109 * Header at the beginning of each V1 address record. This is followed by the
110 * bytes of the address, 4 for IPV4 and 16 for IPV6.
111 */
112struct dns_server_list_v1_address {
113 __u8 address_type; /* enum dns_payload_address_type */
114} __packed;
115
116#endif /* _UAPI_LINUX_DNS_RESOLVER_H */
net/dns_resolver/dns_key.c+64−3
@@ -29,6 +29,7 @@ · 28 unmodified lines
29#include <linux/keyctl.h>29#include <linux/keyctl.h>
30#include <linux/err.h>30#include <linux/err.h>
31#include <linux/seq_file.h>31#include <linux/seq_file.h>
32#include <linux/dns_resolver.h>
32#include <keys/dns_resolver-type.h>33#include <keys/dns_resolver-type.h>
33#include <keys/user-type.h>34#include <keys/user-type.h>
34#include "internal.h"35#include "internal.h"
@@ -48,27 +49,86 @@ const struct cred *dns_resolver_cache; · 13 unmodified lines
48/*49/*
49 * Preparse instantiation data for a dns_resolver key.50 * Preparse instantiation data for a dns_resolver key.
50 *51 *
51 * The data must be a NUL-terminated string, with the NUL char accounted in52 * For normal hostname lookups, the data must be a NUL-terminated string, with
52 * datalen.53 * the NUL char accounted in datalen.
53 *54 *
54 * If the data contains a '#' characters, then we take the clause after each55 * If the data contains a '#' characters, then we take the clause after each
55 * one to be an option of the form 'key=value'. The actual data of interest is56 * one to be an option of the form 'key=value'. The actual data of interest is
56 * the string leading up to the first '#'. For instance:57 * the string leading up to the first '#'. For instance:
57 *58 *
58 * "ip1,ip2,...#foo=bar"59 * "ip1,ip2,...#foo=bar"
60 *
61 * For server list requests, the data must begin with a NUL char and be
62 * followed by a byte indicating the version of the data format. Version 1
63 * looks something like (note this is packed):
64 *
65 * u8 Non-string marker (ie. 0)
66 * u8 Content (DNS_PAYLOAD_IS_*)
67 * u8 Version (e.g. 1)
68 * u8 Source of server list
69 * u8 Lookup status of server list
70 * u8 Number of servers
71 * foreach-server {
72 * __le16 Name length
73 * __le16 Priority (as per SRV record, low first)
74 * __le16 Weight (as per SRV record, higher first)
75 * __le16 Port
76 * u8 Source of address list
77 * u8 Lookup status of address list
78 * u8 Protocol (DNS_SERVER_PROTOCOL_*)
79 * u8 Number of addresses
80 * char[] Name (not NUL-terminated)
81 * foreach-address {
82 * u8 Family (DNS_ADDRESS_IS_*)
83 * union {
84 * u8[4] ipv4_addr
85 * u8[16] ipv6_addr
86 * }
87 * }
88 * }
89 *
59 */90 */
60static int91static int
61dns_resolver_preparse(struct key_preparsed_payload *prep)92dns_resolver_preparse(struct key_preparsed_payload *prep)
62{93{
94 const struct dns_payload_header *bin;
63 struct user_key_payload *upayload;95 struct user_key_payload *upayload;
64 unsigned long derrno;96 unsigned long derrno;
65 int ret;97 int ret;
66 int datalen = prep->datalen, result_len = 0;98 int datalen = prep->datalen, result_len = 0;
67 const char *data = prep->data, *end, *opt;99 const char *data = prep->data, *end, *opt;
68 100
101 if (datalen <= 1 || !data)
102 return -EINVAL;
103
104 if (data[0] == 0) {
105 /* It may be a server list. */
106 if (datalen <= sizeof(*bin))
107 return -EINVAL;
108
109 bin = (const struct dns_payload_header *)data;
110 kenter("[%u,%u],%u", bin->content, bin->version, datalen);
111 if (bin->content != DNS_PAYLOAD_IS_SERVER_LIST) {
112 pr_warn_ratelimited(
113 "dns_resolver: Unsupported content type (%u)\n",
114 bin->content);
115 return -EINVAL;
116 }
117
118 if (bin->version != 1) {
119 pr_warn_ratelimited(
120 "dns_resolver: Unsupported server list version (%u)\n",
121 bin->version);
122 return -EINVAL;
123 }
124
125 result_len = datalen;
126 goto store_result;
127 }
128
69 kenter("'%*.*s',%u", datalen, datalen, data, datalen);129 kenter("'%*.*s',%u", datalen, datalen, data, datalen);
70 130
71 if (datalen <= 1 || !data || data[datalen - 1] != '\0')131 if (!data || data[datalen - 1] != '\0')
72 return -EINVAL;132 return -EINVAL;
73 datalen--;133 datalen--;
74 134
@@ -144,6 +204,7 @@ dns_resolver_preparse(struct key_preparsed_payload *prep) · 69 unmodified lines
144 return 0;204 return 0;
145 }205 }
146 206
207store_result:
147 kdebug("store result");208 kdebug("store result");
148 prep->quotalen = result_len;209 prep->quotalen = result_len;
149 210
net/dns_resolver/dns_query.c+1−4
@@ -148,12 +148,9 @@ int dns_query(const char *type, const char *name, size_t namelen, · 147 unmodified lines
148 148
149 if (_result) {149 if (_result) {
150 ret = -ENOMEM;150 ret = -ENOMEM;
151 *_result = kmalloc(len + 1, GFP_KERNEL);151 *_result = kmemdup_nul(upayload->data, len, GFP_KERNEL);
152 if (!*_result)152 if (!*_result)
153 goto put;153 goto put;
154
155 memcpy(*_result, upayload->data, len);
156 (*_result)[len] = '\0';
157 }154 }
158 155
159 if (_expiry)156 if (_expiry)

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t