1
ssl.patch by Mikael Magnusson <mikma@users.sourceforge.net>
3
Patch adds support for IPv6 to the ssl application.
5
--- erlang-12.b.3-dfsg.orig/erts/configure.in
6
+++ erlang-12.b.3-dfsg/erts/configure.in
10
AC_CHECK_FUNCS([getnameinfo getipnodebyname getipnodebyaddr gethostbyname2])
11
+AC_CHECK_FUNCS([inet_pton])
12
+AC_CHECK_TYPES([struct sockaddr_storage],,,[#include <netinet/in.h>])
14
AC_CHECK_FUNCS([ieee_handler fpsetmask finite isnan isinf res_gethostbyname dlopen \
15
pread pwrite writev memmove strerror strerror_r strncasecmp \
16
--- erlang-12.b.3-dfsg.orig/erts/config.h.in
17
+++ erlang-12.b.3-dfsg/erts/config.h.in
19
/* Define if ipv6 is present */
22
+/* Define to 1 if you have the `inet_pton' function. */
23
+#undef HAVE_INET_PTON
25
/* Define to 1 if you have the <inttypes.h> header file. */
26
#undef HAVE_INTTYPES_H
29
/* Define to 1 if `ssh_data' is member of `struct sctp_send_failed'. */
30
#undef HAVE_STRUCT_SCTP_SEND_FAILED_SSH_DATA
32
+/* Define to 1 if the system has the type `struct sockaddr_storage'. */
33
+#undef HAVE_STRUCT_SOCKADDR_STORAGE
35
/* Define to 1 if you have the <syslog.h> header file. */
38
--- erlang-12.b.3-dfsg.orig/lib/ssl/c_src/esock.c
39
+++ erlang-12.b.3-dfsg/lib/ssl/c_src/esock.c
41
#define INADDR_NONE 0xffffffff /* Should be in <netinet/in.h>. */
44
+#if defined(HAVE_STRUCT_SOCKADDR_STORAGE) && defined(HAVE_GETNAMEINFO) && \
45
+ defined(HAVE_INET_PTON)
51
#include "esock_utils.h"
53
static void dump_connections(void);
54
static int check_num_sock_fds(FD fd);
55
static void safe_close(FD fd);
57
+#if defined(USE_IPV6)
58
+static FD do_connect6(char *lipstring, int lport, char *fipstring, int fport);
59
+static FD do_listen6(char *ipstring, int lport, int backlog, int *aport);
60
+static int ss_getport(const struct sockaddr *sa, socklen_t size);
61
+static int reply_sockaddr(int cmd, int fd, const struct sockaddr *sa,
65
static Connection *new_connection(int state, FD fd);
66
static Connection *get_connection(FD fd);
67
static void remove_connection(Connection *conn);
69
char *protocol_vsn, *cipher;
70
unsigned char *cert, *bin;
72
+#if defined(USE_IPV6)
73
+ struct sockaddr_storage iserv_addr;
75
struct sockaddr_in iserv_addr;
78
Connection *cp, *cpnext, *newcp;
81
/* Add to pending proxy connections */
82
SET_NONBLOCKING(proxysock);
83
pp = new_proxy(proxysock);
84
+#if defined(USE_IPV6)
86
+ ss_getport((struct sockaddr *)&iserv_addr, length);
88
pp->peer_port = ntohs(iserv_addr.sin_port);
90
DEBUGF(("-----------------------------------\n"));
91
DEBUGF(("[PROXY_LISTEN_SOCK] conn accepted: "
94
* reply = {cmd(1), fd(4), port(2),
97
+#if defined(USE_IPV6)
98
+ reply_sockaddr(ESOCK_GETPEERNAME_REP, fd,
99
+ (struct sockaddr*)&iserv_addr, length);
101
reply(ESOCK_GETPEERNAME_REP, "42s", fd,
102
ntohs(iserv_addr.sin_port),
103
inet_ntoa(iserv_addr.sin_addr));
109
* reply = {cmd(1), fd(4), port(2),
112
+#if defined(USE_IPV6)
113
+ reply_sockaddr(ESOCK_GETSOCKNAME_REP, fd,
114
+ (struct sockaddr*)&iserv_addr, length);
116
reply(ESOCK_GETSOCKNAME_REP, "42s", fd,
117
ntohs(iserv_addr.sin_port),
118
inet_ntoa(iserv_addr.sin_addr));
125
DEBUGF(("-> PASSIVE_LISTENING (fd = %d)\n", listensock));
126
/* Publish listensock */
127
- reply(ESOCK_LISTEN_REP, "442", intref, listensock,
128
- ntohs(iserv_addr.sin_port));
129
+ reply(ESOCK_LISTEN_REP, "442", intref, listensock, lport);
132
case ESOCK_TRANSPORT_ACCEPT_CMD:
133
@@ -1513,6 +1545,11 @@
134
struct sockaddr_in sock_addr;
138
+#if defined(USE_IPV6)
139
+ if (strchr(fipstring, ':'))
140
+ return do_connect6(lipstring, lport, fipstring, fport);
143
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_FD) {
144
DEBUGF(("Error calling socket()\n"));
145
@@ -1570,9 +1607,14 @@
146
static int one = 1; /* Type must be int, not long */
147
struct sockaddr_in sock_addr;
150
+ unsigned int length;
153
+#if defined(USE_IPV6)
154
+ if (strchr(ipstring, ':'))
155
+ return do_listen6(ipstring, lport, backlog, aport);
158
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_FD) {
159
DEBUGF(("Error calling socket()\n"));
161
@@ -1628,6 +1670,145 @@
165
+#if defined(USE_IPV6)
166
+static FD do_connect6(char *lipstring, int lport, char *fipstring, int fport)
168
+ struct sockaddr_in6 sock_addr;
171
+ if ((fd = socket(AF_INET6, SOCK_STREAM, 0)) == INVALID_FD) {
172
+ DEBUGF(("Error calling socket()\n"));
175
+ if (check_num_sock_fds(fd) < 0)
177
+ DEBUGF((" fd = %d\n", fd));
179
+ memset(&sock_addr, 0, sizeof(sock_addr));
181
+ if (inet_pton(AF_INET6, lipstring, &sock_addr.sin6_addr) <= 0) {
182
+ DEBUGF(("Error in inet_pton(): lipstring = %s\n", lipstring));
184
+ sock_set_errno(ERRNO_ADDRNOTAVAIL);
187
+ sock_addr.sin6_family = AF_INET6;
188
+ sock_addr.sin6_port = htons(lport);
189
+ if(bind(fd, (struct sockaddr*) &sock_addr, sizeof(sock_addr)) < 0) {
190
+ DEBUGF(("Error in bind()\n"));
192
+ /* XXX Set error code for bind error */
197
+ memset(&sock_addr, 0, sizeof(sock_addr));
198
+ if (inet_pton(AF_INET6, fipstring, &sock_addr.sin6_addr) <= 0) {
199
+ DEBUGF(("Error in inet_pton(): fipstring = %s\n", fipstring));
201
+ sock_set_errno(ERRNO_ADDRNOTAVAIL);
204
+ sock_addr.sin6_family = AF_INET6;
205
+ sock_addr.sin6_port = htons(fport);
207
+ SET_NONBLOCKING(fd);
209
+ if(connect(fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)) < 0) {
210
+ if (sock_errno() != ERRNO_PROGRESS && /* UNIX */
211
+ sock_errno() != ERRNO_BLOCK) { /* WIN32 */
212
+ DEBUGF(("Error in connect()\n"));
220
+static FD do_listen6(char *ipstring, int lport, int backlog, int *aport)
222
+ static int one = 1; /* Type must be int, not long */
223
+ struct sockaddr_in6 sock_addr;
227
+ if ((fd = socket(AF_INET6, SOCK_STREAM, 0)) == INVALID_FD) {
228
+ DEBUGF(("Error calling socket()\n"));
231
+ if (check_num_sock_fds(fd) < 0)
233
+ DEBUGF((" fd = %d\n", fd));
234
+ memset(&sock_addr, 0, sizeof(sock_addr));
235
+ if (inet_pton(AF_INET6, ipstring, &sock_addr.sin6_addr) <= 0) {
236
+ DEBUGF(("Error in inet_pton(): ipstring = %s\n", ipstring));
238
+ sock_set_errno(ERRNO_ADDRNOTAVAIL);
241
+ sock_addr.sin6_family = AF_INET6;
242
+ sock_addr.sin6_port = htons(lport);
244
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one));
246
+ if(bind(fd, (struct sockaddr*) &sock_addr, sizeof(sock_addr)) < 0) {
247
+ DEBUGF(("Error in bind()\n"));
251
+ if (listen(fd, backlog) < 0) {
252
+ DEBUGF(("Error in listen()\n"));
256
+ /* find out assigned local port number */
257
+ length = sizeof(sock_addr);
258
+ if (getsockname(fd, (struct sockaddr *)&sock_addr, &length) < 0) {
259
+ DEBUGF(("Error in getsockname()\n"));
264
+ *aport = ntohs(sock_addr.sin6_port);
268
+static int reply_sockaddr(int cmd, int fd, const struct sockaddr *sa,
271
+ char addr[INET6_ADDRSTRLEN+1] = "";
272
+ char port[10] = "";
275
+ res = getnameinfo(sa, size,
276
+ addr, sizeof(addr), port, sizeof(port),
277
+ NI_NUMERICHOST | NI_NUMERICSERV);
279
+ if (res != EAI_SYSTEM) {
280
+ sock_set_errno(ERRNO_INVAL);
282
+ return reply(cmd, "4s", fd, psx_errstr());
284
+ return reply(cmd, "42s", fd, atoi(port), addr);
288
+static int ss_getport(const struct sockaddr *sa, socklen_t size)
290
+ char port[10] = "";
293
+ res = getnameinfo(sa, size,
294
+ NULL, 0, port, sizeof(port), NI_NUMERICSERV);
304
static Connection *new_connection(int state, FD fd)
307
--- erlang-12.b.3-dfsg.orig/lib/ssl/src/ssl_broker.erl
308
+++ erlang-12.b.3-dfsg/lib/ssl/src/ssl_broker.erl
310
debug(St, "peername: client = ~w~n", [Client]),
311
Reply = case ssl_server:peername(St#st.fd) of
312
{ok, {Address, Port}} ->
313
- {ok, At} = inet_parse:ipv4_address(Address),
314
+ {ok, At} = inet_parse:address(Address),
319
debug(St, "sockname: client = ~w~n", [Client]),
320
Reply = case ssl_server:sockname(St#st.fd) of
321
{ok, {Address, Port}} ->
322
- {ok, At} = inet_parse:ipv4_address(Address),
323
+ {ok, At} = inet_parse:address(Address),
328
SSLOpts = get_ssl_opts(Opts),
329
FlagStr =mk_ssl_optstr(SSLOpts),
330
BackLog = get_backlog(LOpts),
331
- IP = get_ip(LOpts),
332
+ Family = get_family(Opts),
333
+ IP = get_ip(LOpts, Family),
334
case ssl_server:listen_prim(ServerName, IP, Port, FlagStr, BackLog) of
335
{ok, ListenFd, _Port0} ->
336
ThisSocket = #sslsocket{fd = ListenFd, pid = self()},
337
@@ -726,10 +727,11 @@
338
COpts = get_tcp_connect_opts(Opts),
339
SSLOpts = get_ssl_opts(Opts),
340
FlagStr = mk_ssl_optstr(SSLOpts),
341
- case inet:getaddr(FAddress, inet) of
342
+ Family = get_family(Opts),
343
+ case inet:getaddr(FAddress, Family) of
345
%% Timeout is gen_server timeout - hence catch
346
- LIP = get_ip(COpts),
347
+ LIP = get_ip(COpts, Family),
348
LPort = get_port(COpts),
349
case (catch ssl_server:connect_prim(ServerName,
350
LIP, LPort, FIP, FPort,
351
@@ -1016,8 +1018,13 @@
353
get_tagged_opt(backlog, Opts, ?DEF_BACKLOG).
356
- get_tagged_opt(ip, Opts, {0, 0, 0, 0}).
357
+get_ip(Opts, Family) ->
360
+ inet -> {0, 0, 0, 0};
361
+ inet6 -> {0, 0, 0, 0, 0, 0, 0, 0}
363
+ get_tagged_opt(ip, Opts, DefaultIp).
366
get_tagged_opt(port, Opts, 0).
367
@@ -1025,6 +1032,9 @@
369
get_tagged_opt(nodelay, Opts, empty).
372
+ get_tagged_opt(family, transform_opts(Opts), inet).
375
%% add_default_*_opts(Opts) -> NOpts
377
@@ -1073,6 +1083,8 @@
378
transform_opt(binary) -> [{mode, binary}];
379
transform_opt(list) -> [{mode, list}];
380
transform_opt({packet, raw}) -> [{packet, 0}];
381
+transform_opt(inet) -> [{family, inet}];
382
+transform_opt(inet6) -> [{family, inet6}];
383
transform_opt(raw) -> [];
384
transform_opt(Opt) -> [Opt].
386
@@ -1080,10 +1092,10 @@
389
is_connect_opt(Opt) ->
390
- is_tcp_connect_opt(Opt) or is_ssl_opt(Opt).
391
+ is_tcp_connect_opt(Opt) or is_ssl_opt(Opt) or is_family_opt(Opt).
393
is_listen_opt(Opt) ->
394
- is_tcp_listen_opt(Opt) or is_ssl_opt(Opt).
395
+ is_tcp_listen_opt(Opt) or is_ssl_opt(Opt) or is_family_opt(Opt).
397
is_tcp_accept_opt(Opt) ->
399
@@ -1139,6 +1151,10 @@
400
is_ssl_opt({cachetimeout, Timeout}) when Timeout >= 0 -> true;
401
is_ssl_opt(_Opt) -> false.
403
+is_family_opt({family, inet}) -> true;
404
+is_family_opt({family, inet6}) -> true;
405
+is_family_opt(_Opt) -> false.
408
is_string(String) when is_list(String) ->
409
lists:all(fun (C) when is_integer(C), 0 =< C, C =< 255 -> true;
410
@@ -1149,11 +1165,20 @@
412
is_ip_address(Addr) when is_tuple(Addr), size(Addr) == 4 ->
413
is_string(tuple_to_list(Addr));
414
+is_ip_address(Addr) when is_tuple(Addr), size(Addr) == 8 ->
415
+ is_ip6_string(tuple_to_list(Addr));
416
is_ip_address(Addr) when is_list(Addr) ->
421
+is_ip6_string(String) when is_list(String) ->
422
+ lists:all(fun (C) when is_integer(C), 0 =< C, C =< 65535 -> true;
428
get_tagged_opt(Tag, Opts, Default) ->
429
case lists:keysearch(Tag, 1, Opts) of
430
{value, {_, Value}} ->
431
--- erlang-12.b.3-dfsg.orig/lib/ssl/src/ssl_prim.erl
432
+++ erlang-12.b.3-dfsg/lib/ssl/src/ssl_prim.erl
434
peername(St) when record(St, st), St#st.status =:= open ->
435
case ssl_server:peername_prim(ssl_server_prim, St#st.fd) of
436
{ok, {Address, Port}} ->
437
- {ok, At} = inet_parse:ipv4_address(Address),
438
+ {ok, At} = inet_parse:address(Address),
443
sockname(St) when record(St, st), St#st.status =:= open ->
444
case ssl_server:sockname_prim(ssl_server_prim, St#st.fd) of
445
{ok, {Address, Port}} ->
446
- {ok, At} = inet_parse:ipv4_address(Address),
447
+ {ok, At} = inet_parse:address(Address),
451
--- erlang-12.b.3-dfsg.orig/lib/ssl/src/ssl_server.erl
452
+++ erlang-12.b.3-dfsg/lib/ssl/src/ssl_server.erl
453
@@ -1375,7 +1375,10 @@
455
ip_to_string({A,B,C,D}) ->
456
[integer_to_list(A),$.,integer_to_list(B),$.,
457
- integer_to_list(C),$.,integer_to_list(D)].
458
+ integer_to_list(C),$.,integer_to_list(D)];
460
+ip_to_string(Addr) when is_tuple(Addr), size(Addr) == 8 ->
461
+ inet_parse:ntoa(Addr).
463
debug(St, Format, Args) ->
464
debug1(St#st.debug, Format, Args).