1%% This Source Code Form is subject to the terms of the Mozilla Public 2%% License, v. 2.0. If a copy of the MPL was not distributed with this 3%% file, You can obtain one at https://mozilla.org/MPL/2.0/. 4%% 5%% Copyright (c) 2007-2021 VMware, Inc. or its affiliates. All rights reserved. 6%% 7 8-module(rabbit_peer_discovery_dns). 9-behaviour(rabbit_peer_discovery_backend). 10 11-include_lib("rabbit_common/include/rabbit.hrl"). 12 13-export([list_nodes/0, supports_registration/0, register/0, unregister/0, 14 post_registration/0, lock/1, unlock/1]). 15%% for tests 16-export([discover_nodes/2, discover_hostnames/2]). 17 18%% 19%% API 20%% 21 22-spec list_nodes() -> 23 {ok, {Nodes :: [node()], rabbit_types:node_type()}}. 24 25list_nodes() -> 26 case application:get_env(rabbit, cluster_formation) of 27 undefined -> 28 {ok, {[], disc}}; 29 {ok, ClusterFormation} -> 30 case proplists:get_value(peer_discovery_dns, ClusterFormation) of 31 undefined -> 32 rabbit_log:warning("Peer discovery backend is set to ~s " 33 "but final config does not contain rabbit.cluster_formation.peer_discovery_dns. " 34 "Cannot discover any nodes because seed hostname is not configured!", 35 [?MODULE]), 36 {ok, {[], disc}}; 37 Proplist -> 38 Hostname = rabbit_data_coercion:to_list(proplists:get_value(hostname, Proplist)), 39 40 {ok, {discover_nodes(Hostname, net_kernel:longnames()), rabbit_peer_discovery:node_type()}} 41 end 42 end. 43 44 45-spec supports_registration() -> boolean(). 46 47supports_registration() -> 48 false. 49 50 51-spec register() -> ok. 52 53register() -> 54 ok. 55 56-spec unregister() -> ok. 57 58unregister() -> 59 ok. 60 61-spec post_registration() -> ok. 62 63post_registration() -> 64 ok. 65 66-spec lock(Node :: atom()) -> not_supported. 67 68lock(_Node) -> 69 not_supported. 70 71-spec unlock(Data :: term()) -> ok. 72 73unlock(_Data) -> 74 ok. 75 76%% 77%% Implementation 78%% 79 80discover_nodes(SeedHostname, LongNamesUsed) -> 81 [list_to_atom(rabbit_peer_discovery:append_node_prefix(H)) || 82 H <- discover_hostnames(SeedHostname, LongNamesUsed)]. 83 84discover_hostnames(SeedHostname, LongNamesUsed) -> 85 lookup(SeedHostname, LongNamesUsed, ipv4) ++ 86 lookup(SeedHostname, LongNamesUsed, ipv6). 87 88decode_record(ipv4) -> 89 a; 90decode_record(ipv6) -> 91 aaaa. 92 93lookup(SeedHostname, LongNamesUsed, IPv) -> 94 IPs = inet_res:lookup(SeedHostname, in, decode_record(IPv)), 95 rabbit_log:info("Addresses discovered via ~s records of ~s: ~s", 96 [string:to_upper(atom_to_list(decode_record(IPv))), 97 SeedHostname, 98 string:join([inet_parse:ntoa(IP) || IP <- IPs], ", ")]), 99 Hosts = [extract_host(inet:gethostbyaddr(A), LongNamesUsed, A) || 100 A <- IPs], 101 lists:filter(fun(E) -> E =/= error end, Hosts). 102 103 104%% long node names are used 105extract_host({ok, {hostent, FQDN, _, _, _, _}}, true, _Address) -> 106 FQDN; 107%% short node names are used 108extract_host({ok, {hostent, FQDN, _, _, _, _}}, false, _Address) -> 109 lists:nth(1, string:tokens(FQDN, ".")); 110extract_host({error, Error}, _, Address) -> 111 rabbit_log:error("Reverse DNS lookup for address ~s failed: ~p", 112 [inet_parse:ntoa(Address), Error]), 113 error. 114