aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaimo Niskanen <[email protected]>2018-04-26 09:37:24 +0200
committerRaimo Niskanen <[email protected]>2018-04-26 15:50:45 +0200
commit5586959ed008c09141689f1e8865476150e48519 (patch)
tree5f4aa3e202a7a38e7f7b4a530bc275221e5f034f
parentba25ad268065f48ad7647464c8f4c237d07d18b1 (diff)
downloadotp-5586959ed008c09141689f1e8865476150e48519.tar.gz
otp-5586959ed008c09141689f1e8865476150e48519.tar.bz2
otp-5586959ed008c09141689f1e8865476150e48519.zip
Allow check for node name
-rw-r--r--lib/kernel/src/dist_util.erl76
-rw-r--r--lib/ssl/src/inet_tls_dist.erl172
-rw-r--r--lib/ssl/test/ssl_dist_bench_SUITE.erl3
3 files changed, 138 insertions, 113 deletions
diff --git a/lib/kernel/src/dist_util.erl b/lib/kernel/src/dist_util.erl
index 402d474c6d..ecc022b28d 100644
--- a/lib/kernel/src/dist_util.erl
+++ b/lib/kernel/src/dist_util.erl
@@ -645,7 +645,7 @@ recv_name(#hs_data{socket = Socket, f_recv = Recv} = HSData) ->
end.
is_node_name(OtherNodeName) ->
- case string:split(OtherNodeName, "@") of
+ case string:split(OtherNodeName, "@", all) of
[Name,Host] ->
(not string:is_empty(Name))
andalso (not string:is_empty(Host));
@@ -654,24 +654,32 @@ is_node_name(OtherNodeName) ->
end.
split_node(Node) ->
- case string:split(listify_node(Node), "@") of
- [Name,Host] = Split ->
- case
- (not string:is_empty(Name))
- andalso (not string:is_empty(Host))
- of
+ Split = string:split(listify(Node), "@", all),
+ case Split of
+ [Name,Host] ->
+ case string:is_empty(Name) of
true ->
- {Name,Host};
+ Split;
false ->
- Split
+ case string:is_empty(Host) of
+ true ->
+ {name,Name};
+ false ->
+ {node,Name,Host}
+ end
end;
- Split ->
- Split
+ [Host] ->
+ case string:is_empty(Host) of
+ true ->
+ Split;
+ false ->
+ {host,Host}
+ end
end.
-%%
-%% check if connecting node is allowed to connect
-%% with allow-node-scheme
+%% Check if connecting node is allowed to connect
+%% with allow-node-scheme. An empty allowed list
+%% allows all nodes.
%%
is_allowed(#hs_data{allowed = []}, Flags, Node, Version) ->
{Flags,list_to_atom(Node),Version};
@@ -686,43 +694,61 @@ is_allowed(#hs_data{allowed = Allowed} = HSData, Flags, Node, Version) ->
?shutdown2(Node, {is_allowed, not_allowed})
end.
-%% Allow Node on Allowed node list, and also if host part
-%% of Node matches Allowed list item. The Allowed list
-%% contains node names or host names.
+%% The allowed list can contain node names, host names
+%% or names before '@', in atom or list form:
+%% [[email protected], "host.example.org", "node@"].
+%% An empty allowed list allows no nodes.
+%%
+%% Allow a node that matches any entry in the allowed list.
+%% Also allow allowed entries as node to match, not from
+%% this module; here the node has to be a valid name.
%%
is_allowed(_Node, []) ->
false;
-is_allowed(Node, [Node|_Allowed]) when is_atom(Node) ->
+is_allowed(Node, [Node|_Allowed]) ->
+ %% Just an optimization
true;
is_allowed(Node, [AllowedNode|Allowed]) ->
case split_node(AllowedNode) of
- {AllowedName,AllowedHost} ->
+ {node,AllowedName,AllowedHost} ->
%% Allowed node name
case split_node(Node) of
- {AllowedName,AllowedHost} ->
+ {node,AllowedName,AllowedHost} ->
true;
_ ->
is_allowed(Node, Allowed)
end;
- [AllowedHost] ->
+ {host,AllowedHost} ->
%% Allowed host name
case split_node(Node) of
- {_,AllowedHost} ->
+ {node,_,AllowedHost} ->
%% Matching Host part
true;
- [AllowedHost] ->
+ {host,AllowedHost} ->
%% Host matches Host
true;
_ ->
is_allowed(Node, Allowed)
end;
+ {name,AllowedName} ->
+ %% Allowed name before '@'
+ case split_node(Node) of
+ {node,AllowedName,_} ->
+ %% Matching Name part
+ true;
+ {name,AllowedName} ->
+ %% Name matches Name
+ true;
+ _ ->
+ is_allowed(Node, Allowed)
+ end;
_ ->
is_allowed(Node, Allowed)
end.
-listify_node(Atom) when is_atom(Atom) ->
+listify(Atom) when is_atom(Atom) ->
atom_to_list(Atom);
-listify_node(Node) when is_list(Node) ->
+listify(Node) when is_list(Node) ->
Node.
publish_type(Flags) ->
diff --git a/lib/ssl/src/inet_tls_dist.erl b/lib/ssl/src/inet_tls_dist.erl
index b084135d1a..3e9828a2fe 100644
--- a/lib/ssl/src/inet_tls_dist.erl
+++ b/lib/ssl/src/inet_tls_dist.erl
@@ -53,7 +53,7 @@ select(Node) ->
gen_select(Driver, Node) ->
case dist_util:split_node(Node) of
- {_,Host} ->
+ {node,_,Host} ->
case Driver:getaddr(Host) of
{ok, _} -> true;
_ -> false
@@ -141,7 +141,7 @@ f_address(SslSocket, Node) ->
case ssl:peername(SslSocket) of
{ok, Address} ->
case dist_util:split_node(Node) of
- {_,Host} ->
+ {node,_,Host} ->
#net_address{
address=Address, host=Host,
protocol=tls, family=inet};
@@ -335,7 +335,11 @@ verify_client(PeerCert, valid_peer, {CertNodesFun,Driver,PeerIP} = S) ->
%% Parse out all node names from the peer's certificate
%%
case CertNodesFun(PeerCert) of
+ undefined ->
+ %% Certificate allows all nodes
+ {valid,S};
[] ->
+ %% Certificate allows no nodes
{fail,cert_missing_node_name};
CertNodes ->
%% Check if the IP address of one of the nodes
@@ -354,10 +358,12 @@ filter_nodes_by_ip(Nodes, Driver, IP) ->
[Node ||
Node <- Nodes,
case dist_util:split_node(Node) of
- {_,Host} ->
+ {node,_,Host} ->
filter_host_by_ip(Host, Driver, IP);
- [Host] ->
- filter_host_by_ip(Host, Driver, IP)
+ {host,Host} ->
+ filter_host_by_ip(Host, Driver, IP);
+ {name,_Name} ->
+ true
end].
filter_host_by_ip(Host, Driver, IP) ->
@@ -452,7 +458,11 @@ allowed_nodes(Driver, CertNodesFun, SslSocket, Allowed) ->
%% Parse out all node names from the peer's certificate
%%
case CertNodesFun(PeerCert) of
+ undefined ->
+ %% Certificate allows all nodes
+ Allowed;
[] ->
+ %% Certificate allows no nodes
?shutdown(cert_missing_node_name);
CertNodes ->
%% Filter out all nodes in the
@@ -615,7 +625,11 @@ verify_server(PeerCert, valid_peer, {CertNodesFun,Node} = S) ->
%% Parse out all node names from the peer's certificate
%%
case CertNodesFun(PeerCert) of
+ undefined ->
+ %% Certificate allows all nodes
+ {valid,S};
[] ->
+ %% Certificate allows no nodes
{fail,cert_missing_node_name};
CertNodes ->
%% Check that the node we are connecting to
@@ -681,32 +695,36 @@ cert_nodes(
parse_extensions(Extensions) when is_list(Extensions) ->
- parse_extensions(Extensions, [], none);
+ parse_extensions(Extensions, [], []);
parse_extensions(asn1_NOVALUE) ->
- [].
+ undefined. % Allow all nodes
%%
-parse_extensions([], Hosts, none) ->
+parse_extensions([], [], []) ->
+ undefined; % Allow all nodes
+parse_extensions([], Hosts, []) ->
lists:reverse(Hosts);
-parse_extensions([], Hosts, Name) ->
- [Name ++ "@" ++ Host || Host <- lists:reverse(Hosts)];
+parse_extensions([], [], Names) ->
+ [Name ++ "@" || Name <- lists:reverse(Names)];
+parse_extensions([], Hosts, Names) ->
+ [Name ++ "@" ++ Host ||
+ Host <- lists:reverse(Hosts),
+ Name <- lists:reverse(Names)];
parse_extensions(
[#'Extension'{
extnID = ?'id-ce-subjectAltName',
extnValue = AltNames}
|Extensions],
- Hosts, Name) ->
+ Hosts, Names) ->
case parse_subject_altname(AltNames) of
none ->
- parse_extensions(Extensions, Hosts, Name);
+ parse_extensions(Extensions, Hosts, Names);
{host,Host} ->
- parse_extensions(Extensions, [Host|Hosts], Name);
- {name,NewName} when Name =:= none ->
- parse_extensions(Extensions, Hosts, NewName);
- {name,_NewName} ->
- parse_extensions(Extensions, Hosts, Name)
+ parse_extensions(Extensions, [Host|Hosts], Names);
+ {name,Name} ->
+ parse_extensions(Extensions, Hosts, [Name|Names])
end;
-parse_extensions([_|Extensions], Hosts, Name) ->
- parse_extensions(Extensions, Hosts, Name).
+parse_extensions([_|Extensions], Hosts, Names) ->
+ parse_extensions(Extensions, Hosts, Names).
parse_subject_altname([]) ->
none;
@@ -742,9 +760,9 @@ parse_rdn([_|Rdn]) ->
%% If Node is illegal terminate the connection setup!!
split_node(Driver, Node, LongOrShortNames) ->
case dist_util:split_node(Node) of
- {Name, Host} ->
- check_node(Driver, Name, Node, Host, LongOrShortNames);
- [_] ->
+ {node, Name, Host} ->
+ check_node(Driver, Node, Name, Host, LongOrShortNames);
+ {host, _} ->
error_logger:error_msg(
"** Nodename ~p illegal, no '@' character **~n",
[Node]),
@@ -755,8 +773,8 @@ split_node(Driver, Node, LongOrShortNames) ->
?shutdown2(Node, trace({illegal_node_name, Node}))
end.
-check_node(Driver, Name, Node, Host, LongOrShortNames) ->
- case string:split(Host, ".") of
+check_node(Driver, Node, Name, Host, LongOrShortNames) ->
+ case string:split(Host, ".", all) of
[_] when LongOrShortNames =:= longnames ->
case Driver:parse_address(Host) of
{ok, _} ->
@@ -824,70 +842,50 @@ get_ssl_dist_arguments(Type) ->
[{erl_dist, true}]
end.
-ssl_options(_,[]) ->
+
+ssl_options(_Type, []) ->
[];
-ssl_options(server, ["client_" ++ _, _Value |T]) ->
- ssl_options(server,T);
-ssl_options(client, ["server_" ++ _, _Value|T]) ->
- ssl_options(client,T);
-ssl_options(server, ["server_certfile", Value|T]) ->
- [{certfile, Value} | ssl_options(server,T)];
-ssl_options(client, ["client_certfile", Value | T]) ->
- [{certfile, Value} | ssl_options(client,T)];
-ssl_options(server, ["server_cacertfile", Value|T]) ->
- [{cacertfile, Value} | ssl_options(server,T)];
-ssl_options(client, ["client_cacertfile", Value|T]) ->
- [{cacertfile, Value} | ssl_options(client,T)];
-ssl_options(server, ["server_keyfile", Value|T]) ->
- [{keyfile, Value} | ssl_options(server,T)];
-ssl_options(client, ["client_keyfile", Value|T]) ->
- [{keyfile, Value} | ssl_options(client,T)];
-ssl_options(server, ["server_password", Value|T]) ->
- [{password, Value} | ssl_options(server,T)];
-ssl_options(client, ["client_password", Value|T]) ->
- [{password, Value} | ssl_options(client,T)];
-ssl_options(server, ["server_verify", Value|T]) ->
- [{verify, atomize(Value)} | ssl_options(server,T)];
-ssl_options(client, ["client_verify", Value|T]) ->
- [{verify, atomize(Value)} | ssl_options(client,T)];
-ssl_options(server, ["server_verify_fun", Value|T]) ->
- [{verify_fun, verify_fun(Value)} | ssl_options(server,T)];
-ssl_options(client, ["client_verify_fun", Value|T]) ->
- [{verify_fun, verify_fun(Value)} | ssl_options(client,T)];
-ssl_options(server, ["server_crl_check", Value|T]) ->
- [{crl_check, atomize(Value)} | ssl_options(server,T)];
-ssl_options(client, ["client_crl_check", Value|T]) ->
- [{crl_check, atomize(Value)} | ssl_options(client,T)];
-ssl_options(server, ["server_crl_cache", Value|T]) ->
- [{crl_cache, termify(Value)} | ssl_options(server,T)];
-ssl_options(client, ["client_crl_cache", Value|T]) ->
- [{crl_cache, termify(Value)} | ssl_options(client,T)];
-ssl_options(server, ["server_reuse_sessions", Value|T]) ->
- [{reuse_sessions, atomize(Value)} | ssl_options(server,T)];
-ssl_options(client, ["client_reuse_sessions", Value|T]) ->
- [{reuse_sessions, atomize(Value)} | ssl_options(client,T)];
-ssl_options(server, ["server_secure_renegotiate", Value|T]) ->
- [{secure_renegotiate, atomize(Value)} | ssl_options(server,T)];
-ssl_options(client, ["client_secure_renegotiate", Value|T]) ->
- [{secure_renegotiate, atomize(Value)} | ssl_options(client,T)];
-ssl_options(server, ["server_depth", Value|T]) ->
- [{depth, list_to_integer(Value)} | ssl_options(server,T)];
-ssl_options(client, ["client_depth", Value|T]) ->
- [{depth, list_to_integer(Value)} | ssl_options(client,T)];
-ssl_options(server, ["server_hibernate_after", Value|T]) ->
- [{hibernate_after, list_to_integer(Value)} | ssl_options(server,T)];
-ssl_options(client, ["client_hibernate_after", Value|T]) ->
- [{hibernate_after, list_to_integer(Value)} | ssl_options(client,T)];
-ssl_options(server, ["server_ciphers", Value|T]) ->
- [{ciphers, Value} | ssl_options(server,T)];
-ssl_options(client, ["client_ciphers", Value|T]) ->
- [{ciphers, Value} | ssl_options(client,T)];
-ssl_options(server, ["server_dhfile", Value|T]) ->
- [{dhfile, Value} | ssl_options(server,T)];
-ssl_options(server, ["server_fail_if_no_peer_cert", Value|T]) ->
- [{fail_if_no_peer_cert, atomize(Value)} | ssl_options(server,T)];
-ssl_options(Type, Opts) ->
- error(malformed_ssl_dist_opt, [Type, Opts]).
+ssl_options(client, ["client_" ++ Opt, Value | T] = Opts) ->
+ ssl_options(client, T, Opts, Opt, Value);
+ssl_options(server, ["server_" ++ Opt, Value | T] = Opts) ->
+ ssl_options(server, T, Opts, Opt, Value);
+ssl_options(Type, [_Opt, _Value | T]) ->
+ ssl_options(Type, T).
+%%
+ssl_options(Type, T, Opts, Opt, Value) ->
+ case ssl_option(Type, Opt) of
+ error ->
+ error(malformed_ssl_dist_opt, [Type, Opts]);
+ Fun ->
+ [{list_to_atom(Opt), Fun(Value)}|ssl_options(Type, T)]
+ end.
+
+ssl_option(server, Opt) ->
+ case Opt of
+ "dhfile" -> fun listify/1;
+ "fail_if_no_peer_cert" -> fun atomize/1;
+ _ -> ssl_option(client, Opt)
+ end;
+ssl_option(client, Opt) ->
+ case Opt of
+ "certfile" -> fun listify/1;
+ "cacertfile" -> fun listify/1;
+ "keyfile" -> fun listify/1;
+ "password" -> fun listify/1;
+ "verify" -> fun atomize/1;
+ "verify_fun" -> fun verify_fun/1;
+ "crl_check" -> fun atomize/1;
+ "crl_cache" -> fun termify/1;
+ "reuse_sessions" -> fun atomize/1;
+ "secure_renegotiate" -> fun atomize/1;
+ "depth" -> fun erlang:list_to_integer/1;
+ "hibernate_after" -> fun erlang:list_to_integer/1;
+ "ciphers" -> fun listify/1;
+ _ -> error
+ end.
+
+listify(List) when is_list(List) ->
+ List.
atomize(List) when is_list(List) ->
list_to_atom(List);
diff --git a/lib/ssl/test/ssl_dist_bench_SUITE.erl b/lib/ssl/test/ssl_dist_bench_SUITE.erl
index 4ffc486fc4..f827ea12bb 100644
--- a/lib/ssl/test/ssl_dist_bench_SUITE.erl
+++ b/lib/ssl/test/ssl_dist_bench_SUITE.erl
@@ -207,7 +207,8 @@ write_node_conf(
#{root => RootCert,
peer =>
[{extensions,
- [#'Extension'{
+ [
+ #'Extension'{
extnID = ?'id-ce-subjectAltName',
extnValue = [{dNSName, Host}],
critical = true},