1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Server address list management
4 * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
8 #include <linux/slab.h>
9 #include <linux/ctype.h>
10 #include <linux/dns_resolver.h>
11 #include <linux/inet.h>
12 #include <keys/rxrpc-type.h>
17 * Release an address list.
19 void afs_put_addrlist(struct afs_addr_list
*alist
)
21 if (alist
&& refcount_dec_and_test(&alist
->usage
))
22 kfree_rcu(alist
, rcu
);
26 * Allocate an address list.
28 struct afs_addr_list
*afs_alloc_addrlist(unsigned int nr
,
29 unsigned short service
,
32 struct afs_addr_list
*alist
;
35 _enter("%u,%u,%u", nr
, service
, port
);
37 if (nr
> AFS_MAX_ADDRESSES
)
38 nr
= AFS_MAX_ADDRESSES
;
40 alist
= kzalloc(struct_size(alist
, addrs
, nr
), GFP_KERNEL
);
44 refcount_set(&alist
->usage
, 1);
45 alist
->max_addrs
= nr
;
47 for (i
= 0; i
< nr
; i
++) {
48 struct sockaddr_rxrpc
*srx
= &alist
->addrs
[i
];
49 srx
->srx_family
= AF_RXRPC
;
50 srx
->srx_service
= service
;
51 srx
->transport_type
= SOCK_DGRAM
;
52 srx
->transport_len
= sizeof(srx
->transport
.sin6
);
53 srx
->transport
.sin6
.sin6_family
= AF_INET6
;
54 srx
->transport
.sin6
.sin6_port
= htons(port
);
61 * Parse a text string consisting of delimited addresses.
63 struct afs_vlserver_list
*afs_parse_text_addrs(struct afs_net
*net
,
64 const char *text
, size_t len
,
66 unsigned short service
,
69 struct afs_vlserver_list
*vllist
;
70 struct afs_addr_list
*alist
;
71 const char *p
, *end
= text
+ len
;
76 _enter("%*.*s,%c", (int)len
, (int)len
, text
, delim
);
79 _leave(" = -EDESTADDRREQ [empty]");
80 return ERR_PTR(-EDESTADDRREQ
);
83 if (delim
== ':' && (memchr(text
, ',', len
) || !memchr(text
, '.', len
)))
86 /* Count the addresses */
102 p
= memchr(p
, ']', end
- p
);
112 p
= memchr(p
, delim
, end
- p
);
118 _debug("%u/%u addresses", nr
, AFS_MAX_ADDRESSES
);
120 vllist
= afs_alloc_vlserver_list(1);
122 return ERR_PTR(-ENOMEM
);
124 vllist
->nr_servers
= 1;
125 vllist
->servers
[0].server
= afs_alloc_vlserver("<dummy>", 7, AFS_VL_PORT
);
126 if (!vllist
->servers
[0].server
)
129 alist
= afs_alloc_addrlist(nr
, service
, AFS_VL_PORT
);
133 /* Extract the addresses */
136 const char *q
, *stop
;
137 unsigned int xport
= port
;
148 q
= memchr(p
, ']', end
- p
);
150 for (q
= p
; q
< end
; q
++)
151 if (*q
== '+' || *q
== delim
)
155 if (in4_pton(p
, q
- p
, (u8
*)&x
[0], -1, &stop
)) {
157 } else if (in6_pton(p
, q
- p
, (u8
*)x
, -1, &stop
)) {
170 if (q
< end
&& *q
== ']')
175 /* Port number specification "+1234" */
178 if (p
>= end
|| !isdigit(*p
)) {
190 } while (p
< end
&& isdigit(*p
));
191 } else if (*p
== delim
) {
199 if (family
== AF_INET
)
200 afs_merge_fs_addr4(alist
, x
[0], xport
);
202 afs_merge_fs_addr6(alist
, x
, xport
);
206 rcu_assign_pointer(vllist
->servers
[0].server
->addresses
, alist
);
207 _leave(" = [nr %u]", alist
->nr_addrs
);
211 _leave(" = -EINVAL [%s %zu %*.*s]",
212 problem
, p
- text
, (int)len
, (int)len
, text
);
213 return ERR_PTR(-EINVAL
);
215 _leave(" = -EINVAL [%s %zu %*.*s]",
216 problem
, p
- text
, (int)len
, (int)len
, text
);
219 afs_put_addrlist(alist
);
221 afs_put_vlserverlist(net
, vllist
);
226 * Compare old and new address lists to see if there's been any change.
227 * - How to do this in better than O(Nlog(N)) time?
228 * - We don't really want to sort the address list, but would rather take the
229 * list as we got it so as not to undo record rotation by the DNS server.
232 static int afs_cmp_addr_list(const struct afs_addr_list
*a1
,
233 const struct afs_addr_list
*a2
)
239 * Perform a DNS query for VL servers and build a up an address list.
241 struct afs_vlserver_list
*afs_dns_query(struct afs_cell
*cell
, time64_t
*_expiry
)
243 struct afs_vlserver_list
*vllist
;
247 _enter("%s", cell
->name
);
249 ret
= dns_query(cell
->net
->net
, "afsdb", cell
->name
, cell
->name_len
,
250 "srv=1", &result
, _expiry
, true);
252 _leave(" = %d [dns]", ret
);
257 *_expiry
= ktime_get_real_seconds() + 60;
259 if (ret
> 1 && result
[0] == 0)
260 vllist
= afs_extract_vlserver_list(cell
, result
, ret
);
262 vllist
= afs_parse_text_addrs(cell
->net
, result
, ret
, ',',
263 VL_SERVICE
, AFS_VL_PORT
);
265 if (IS_ERR(vllist
) && vllist
!= ERR_PTR(-ENOMEM
))
266 pr_err("Failed to parse DNS data %ld\n", PTR_ERR(vllist
));
272 * Merge an IPv4 entry into a fileserver address list.
274 void afs_merge_fs_addr4(struct afs_addr_list
*alist
, __be32 xdr
, u16 port
)
276 struct sockaddr_rxrpc
*srx
;
277 u32 addr
= ntohl(xdr
);
280 if (alist
->nr_addrs
>= alist
->max_addrs
)
283 for (i
= 0; i
< alist
->nr_ipv4
; i
++) {
284 struct sockaddr_in
*a
= &alist
->addrs
[i
].transport
.sin
;
285 u32 a_addr
= ntohl(a
->sin_addr
.s_addr
);
286 u16 a_port
= ntohs(a
->sin_port
);
288 if (addr
== a_addr
&& port
== a_port
)
290 if (addr
== a_addr
&& port
< a_port
)
296 if (i
< alist
->nr_addrs
)
297 memmove(alist
->addrs
+ i
+ 1,
299 sizeof(alist
->addrs
[0]) * (alist
->nr_addrs
- i
));
301 srx
= &alist
->addrs
[i
];
302 srx
->srx_family
= AF_RXRPC
;
303 srx
->transport_type
= SOCK_DGRAM
;
304 srx
->transport_len
= sizeof(srx
->transport
.sin
);
305 srx
->transport
.sin
.sin_family
= AF_INET
;
306 srx
->transport
.sin
.sin_port
= htons(port
);
307 srx
->transport
.sin
.sin_addr
.s_addr
= xdr
;
313 * Merge an IPv6 entry into a fileserver address list.
315 void afs_merge_fs_addr6(struct afs_addr_list
*alist
, __be32
*xdr
, u16 port
)
317 struct sockaddr_rxrpc
*srx
;
320 if (alist
->nr_addrs
>= alist
->max_addrs
)
323 for (i
= alist
->nr_ipv4
; i
< alist
->nr_addrs
; i
++) {
324 struct sockaddr_in6
*a
= &alist
->addrs
[i
].transport
.sin6
;
325 u16 a_port
= ntohs(a
->sin6_port
);
327 diff
= memcmp(xdr
, &a
->sin6_addr
, 16);
328 if (diff
== 0 && port
== a_port
)
330 if (diff
== 0 && port
< a_port
)
336 if (i
< alist
->nr_addrs
)
337 memmove(alist
->addrs
+ i
+ 1,
339 sizeof(alist
->addrs
[0]) * (alist
->nr_addrs
- i
));
341 srx
= &alist
->addrs
[i
];
342 srx
->srx_family
= AF_RXRPC
;
343 srx
->transport_type
= SOCK_DGRAM
;
344 srx
->transport_len
= sizeof(srx
->transport
.sin6
);
345 srx
->transport
.sin6
.sin6_family
= AF_INET6
;
346 srx
->transport
.sin6
.sin6_port
= htons(port
);
347 memcpy(&srx
->transport
.sin6
.sin6_addr
, xdr
, 16);
352 * Get an address to try.
354 bool afs_iterate_addresses(struct afs_addr_cursor
*ac
)
356 unsigned long set
, failed
;
362 set
= ac
->alist
->responded
;
363 failed
= ac
->alist
->failed
;
364 _enter("%lx-%lx-%lx,%d", set
, failed
, ac
->tried
, ac
->index
);
368 set
&= ~(failed
| ac
->tried
);
373 index
= READ_ONCE(ac
->alist
->preferred
);
374 if (test_bit(index
, &set
))
381 set_bit(index
, &ac
->tried
);
382 ac
->responded
= false;
387 * Release an address list cursor.
389 int afs_end_cursor(struct afs_addr_cursor
*ac
)
391 struct afs_addr_list
*alist
;
396 ac
->index
!= alist
->preferred
&&
397 test_bit(ac
->alist
->preferred
, &ac
->tried
))
398 WRITE_ONCE(alist
->preferred
, ac
->index
);
399 afs_put_addrlist(alist
);