aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2018-07-24 16:11:32 +0200
committerMicael Karlberg <[email protected]>2018-09-18 14:50:18 +0200
commitb9237c96b2b86c82bb128625cc532b3528222560 (patch)
tree0207f6fc08722890675f17b6c126e25c9a9e70aa
parent7d5b6e7bf640eb5d64679e3bf7b440b8e21e3a4d (diff)
downloadotp-b9237c96b2b86c82bb128625cc532b3528222560.tar.gz
otp-b9237c96b2b86c82bb128625cc532b3528222560.tar.bz2
otp-b9237c96b2b86c82bb128625cc532b3528222560.zip
[socket-nif] Add support for socket (level ipv6) option addrform
Added support for the IPv6 socket option ADDRFORM. Only allowed for IPv6 sockets that are connected and bound to a v4-mapped-on-v6 address. OTP-14831.
-rw-r--r--erts/doc/src/socket_usage.xml8
-rw-r--r--erts/emulator/nifs/common/socket_nif.c54
-rw-r--r--erts/preloaded/ebin/socket.beambin57952 -> 58020 bytes
-rw-r--r--erts/preloaded/src/socket.erl8
4 files changed, 67 insertions, 3 deletions
diff --git a/erts/doc/src/socket_usage.xml b/erts/doc/src/socket_usage.xml
index 1423571f5c..8480af315e 100644
--- a/erts/doc/src/socket_usage.xml
+++ b/erts/doc/src/socket_usage.xml
@@ -412,6 +412,14 @@
<cell><em>Other</em></cell>
</row>
<row>
+ <cell>addrform</cell>
+ <cell>inet</cell>
+ <cell>yes</cell>
+ <cell>no</cell>
+ <cell>allowed only for IPv6 sockets that are connected and bound to a
+ v4-mapped-on-v6 address</cell>
+ </row>
+ <row>
<cell>add_membership</cell>
<cell>ipv6_mreq()</cell>
<cell>yes</cell>
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index 4d78e89a4f..f7053d77fa 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -537,6 +537,7 @@ typedef union {
#define SOCKET_OPT_IP_TTL 32
#define SOCKET_OPT_IP_UNBLOCK_SOURCE 33
+#define SOCKET_OPT_IPV6_ADDRFORM 1
#define SOCKET_OPT_IPV6_ADD_MEMBERSHIP 2
#define SOCKET_OPT_IPV6_AUTHHDR 3
#define SOCKET_OPT_IPV6_DROP_MEMBERSHIP 6
@@ -1204,6 +1205,11 @@ static ERL_NIF_TERM nsetopt_lvl_ipv6(ErlNifEnv* env,
SocketDescriptor* descP,
int eOpt,
ERL_NIF_TERM eVal);
+#if defined(IPV6_ADDRFORM)
+static ERL_NIF_TERM nsetopt_lvl_ipv6_addrform(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
#if defined(IPV6_ADD_MEMBERSHIP)
static ERL_NIF_TERM nsetopt_lvl_ipv6_add_membership(ErlNifEnv* env,
SocketDescriptor* descP,
@@ -5607,6 +5613,12 @@ ERL_NIF_TERM nsetopt_lvl_ipv6(ErlNifEnv* env,
"\r\n", eOpt) );
switch (eOpt) {
+#if defined(IPV6_ADDRFORM)
+ case SOCKET_OPT_IPV6_ADDRFORM:
+ result = nsetopt_lvl_ipv6_addrform(env, descP, eVal);
+ break;
+#endif
+
#if defined(IPV6_ADD_MEMBERSHIP)
case SOCKET_OPT_IPV6_ADD_MEMBERSHIP:
result = nsetopt_lvl_ipv6_add_membership(env, descP, eVal);
@@ -5725,6 +5737,48 @@ ERL_NIF_TERM nsetopt_lvl_ipv6(ErlNifEnv* env,
}
+#if defined(IPV6_ADDRFORM)
+static
+ERL_NIF_TERM nsetopt_lvl_ipv6_addrform(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ ERL_NIF_TERM result;
+ int res, edomain, domain;
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_ipv6_addrform -> entry with"
+ "\r\n eVal: %T"
+ "\r\n", eVal) );
+
+ if (!GET_INT(env, eVal, &edomain))
+ return esock_make_error(env, esock_atom_einval);
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_ipv6_addrform -> decode"
+ "\r\n edomain: %d"
+ "\r\n", edomain) );
+
+ if (!edomain2domain(edomain, &domain))
+ return esock_make_error(env, esock_atom_einval);
+
+ SSDBG( descP, ("SOCKET", "nsetopt_lvl_ipv6_addrform -> try set opt to %d\r\n",
+ domain) );
+
+ res = socket_setopt(descP->sock,
+ SOL_IPV6, IPV6_ADDRFORM,
+ &domain, sizeof(domain));
+
+ if (res != 0)
+ result = esock_make_error_errno(env, sock_errno());
+ else
+ result = esock_atom_ok;
+
+ return result;
+}
+#endif
+
+
#if defined(IPV6_ADD_MEMBERSHIP)
static
ERL_NIF_TERM nsetopt_lvl_ipv6_add_membership(ErlNifEnv* env,
diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam
index cdc403055b..20f2cf659b 100644
--- a/erts/preloaded/ebin/socket.beam
+++ b/erts/preloaded/ebin/socket.beam
Binary files differ
diff --git a/erts/preloaded/src/socket.erl b/erts/preloaded/src/socket.erl
index 82a51ee245..0c3a17b54d 100644
--- a/erts/preloaded/src/socket.erl
+++ b/erts/preloaded/src/socket.erl
@@ -635,7 +635,7 @@
-define(SOCKET_OPT_IP_TTL, 32).
-define(SOCKET_OPT_IP_UNBLOCK_SOURCE, 33).
-%% -define(SOCKET_OPT_IPV6_ADDFORM, 1).
+-define(SOCKET_OPT_IPV6_ADDRFORM, 1).
-define(SOCKET_OPT_IPV6_ADD_MEMBERSHIP, 2).
-define(SOCKET_OPT_IPV6_AUTHHDR, 3). % Obsolete?
%% -define(SOCKET_OPT_IPV6_AUTH_LEVEL, 4).
@@ -2254,6 +2254,8 @@ enc_setopt_value(ip, unblock_source, #{multiaddr := MA,
enc_setopt_value(ip = L, Opt, V, _D, _T, _P) ->
not_supported({L, Opt, V});
+enc_setopt_value(ipv6, addrform, inet = V, _D, _T, _P) ->
+ enc_domain(V);
enc_setopt_value(ipv6, add_membership, #{multiaddr := MA,
interface := IF} = V, _D, _T, _P)
when ((is_tuple(MA) andalso (size(MA) =:= 8)) andalso
@@ -2704,8 +2706,8 @@ enc_sockopt_key(ip = L, UnknownOpt, _Dir, _D, _T, _P) ->
unknown({L, UnknownOpt});
%% IPv6 socket options
-enc_sockopt_key(ipv6 = L, addrform = Opt, set = _Dir, _D, _T, _P) ->
- not_supported({L, Opt});
+enc_sockopt_key(ipv6 = _L, addrform = _Opt, set = _Dir, _D, _T, _P) ->
+ ?SOCKET_OPT_IPV6_ADDRFORM;
enc_sockopt_key(ipv6, add_membership = _Opt, set = _Dir, _D, _T, _P) ->
?SOCKET_OPT_IPV6_ADD_MEMBERSHIP;
enc_sockopt_key(ipv6 = _L, authhdr = _Opt, _Dir, _D, T, _P)