Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
L
libzmq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
libzmq
Commits
22025872
Unverified
Commit
22025872
authored
Jun 10, 2019
by
Luca Boccassi
Committed by
GitHub
Jun 10, 2019
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3534 from guillon/dev-socks-basic-auth
Implement SOCKS5 basic authentication
parents
68558bc3
58c30dc7
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
309 additions
and
21 deletions
+309
-21
zmq_setsockopt.txt
doc/zmq_setsockopt.txt
+36
-4
zmq.h
include/zmq.h
+2
-0
options.cpp
src/options.cpp
+26
-0
options.hpp
src/options.hpp
+6
-0
session_base.cpp
src/session_base.cpp
+7
-1
socks.cpp
src/socks.cpp
+90
-0
socks.hpp
src/socks.hpp
+44
-0
socks_connecter.cpp
src/socks_connecter.cpp
+76
-15
socks_connecter.hpp
src/socks_connecter.hpp
+20
-1
zmq_draft.h
src/zmq_draft.h
+2
-0
No files found.
doc/zmq_setsockopt.txt
View file @
22025872
...
...
@@ -891,10 +891,42 @@ Applicable socket types:: all
ZMQ_SOCKS_PROXY: Set SOCKS5 proxy address
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the SOCKS5 proxy address that shall be used by the socket for the TCP
connection(s). Does not support SOCKS5 authentication. If the endpoints are
domain names instead of addresses they shall not be resolved and they shall
be forwarded unchanged to the SOCKS proxy service in the client connection
request message (address type 0x03 domain name).
connection(s). Supported authentication methods are: no authentication
or basic authentication when setup with ZMQ_SOCKS_USERNAME. If the endpoints
are domain names instead of addresses they shall not be resolved and they
shall be forwarded unchanged to the SOCKS proxy service in the client
connection request message (address type 0x03 domain name).
[horizontal]
Option value type:: character string
Option value unit:: N/A
Default value:: not set
Applicable socket types:: all, when using TCP transport
ZMQ_SOCKS_USERNAME: Set SOCKS username and select basic authentication
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the username for authenticated connection to the SOCKS5 proxy.
If you set this to a non-null and non-empty value, the authentication
method used for the SOCKS5 connection shall be basic authentication.
In this case, use ZMQ_SOCKS_PASSWORD option in order to set the password.
If you set this to a null value or empty value, the authentication method
shall be no authentication, the default.
[horizontal]
Option value type:: character string
Option value unit:: N/A
Default value:: not set
Applicable socket types:: all, when using TCP transport
ZMQ_SOCKS_PASSWORD: Set SOCKS basic authentication password
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the password for authenticating to the SOCKS5 proxy server.
This is used only when the SOCKS5 authentication method has been
set to basic authentication through the ZMQ_SOCKS_USERNAME option.
Setting this to a null value (the default) is equivalent to an
empty password string.
[horizontal]
Option value type:: character string
...
...
include/zmq.h
View file @
22025872
...
...
@@ -656,6 +656,8 @@ ZMQ_EXPORT void zmq_threadclose (void *thread_);
#define ZMQ_MULTICAST_LOOP 96
#define ZMQ_ROUTER_NOTIFY 97
#define ZMQ_XPUB_MANUAL_LAST_VALUE 98
#define ZMQ_SOCKS_USERNAME 99
#define ZMQ_SOCKS_PASSWORD 100
/* DRAFT Context options */
#define ZMQ_ZERO_COPY_RECV 10
...
...
src/options.cpp
View file @
22025872
...
...
@@ -461,6 +461,24 @@ int zmq::options_t::setsockopt (int option_,
return
do_setsockopt_string_allow_empty_strict
(
optval_
,
optvallen_
,
&
socks_proxy_address
,
SIZE_MAX
);
case
ZMQ_SOCKS_USERNAME
:
/* Make empty string or NULL equivalent. */
if
(
optval_
==
NULL
||
optvallen_
==
0
)
{
socks_proxy_username
.
clear
();
return
0
;
}
else
{
return
do_setsockopt_string_allow_empty_strict
(
optval_
,
optvallen_
,
&
socks_proxy_username
,
255
);
}
case
ZMQ_SOCKS_PASSWORD
:
/* Make empty string or NULL equivalent. */
if
(
optval_
==
NULL
||
optvallen_
==
0
)
{
socks_proxy_password
.
clear
();
return
0
;
}
else
{
return
do_setsockopt_string_allow_empty_strict
(
optval_
,
optvallen_
,
&
socks_proxy_password
,
255
);
}
case
ZMQ_TCP_KEEPALIVE
:
if
(
is_int
&&
(
value
==
-
1
||
value
==
0
||
value
==
1
))
{
tcp_keepalive
=
value
;
...
...
@@ -959,6 +977,14 @@ int zmq::options_t::getsockopt (int option_,
return
do_getsockopt
(
optval_
,
optvallen_
,
socks_proxy_address
);
break
;
case
ZMQ_SOCKS_USERNAME
:
return
do_getsockopt
(
optval_
,
optvallen_
,
socks_proxy_username
);
break
;
case
ZMQ_SOCKS_PASSWORD
:
return
do_getsockopt
(
optval_
,
optvallen_
,
socks_proxy_password
);
break
;
case
ZMQ_TCP_KEEPALIVE
:
if
(
is_int
)
{
*
value
=
tcp_keepalive
;
...
...
src/options.hpp
View file @
22025872
...
...
@@ -159,6 +159,12 @@ struct options_t
// Address of SOCKS proxy
std
::
string
socks_proxy_address
;
// Credentials for SOCKS proxy.
// Conneciton method will be basic auth if username
// is not empty, no auth otherwise.
std
::
string
socks_proxy_username
;
std
::
string
socks_proxy_password
;
// TCP keep-alive settings.
// Defaults to -1 = do not change socket options
int
tcp_keepalive
;
...
...
src/session_base.cpp
View file @
22025872
...
...
@@ -668,8 +668,14 @@ zmq::own_t *zmq::session_base_t::create_connecter_tcp (io_thread_t *io_thread_,
address_t
*
proxy_address
=
new
(
std
::
nothrow
)
address_t
(
protocol_name
::
tcp
,
options
.
socks_proxy_address
,
this
->
get_ctx
());
alloc_assert
(
proxy_address
);
return
new
(
std
::
nothrow
)
socks_connecter_t
(
socks_connecter_t
*
connecter
=
new
(
std
::
nothrow
)
socks_connecter_t
(
io_thread_
,
this
,
options
,
_addr
,
proxy_address
,
wait_
);
alloc_assert
(
connecter
);
if
(
!
options
.
socks_proxy_username
.
empty
())
{
connecter
->
set_auth_method_basic
(
options
.
socks_proxy_username
,
options
.
socks_proxy_password
);
}
return
connecter
;
}
return
new
(
std
::
nothrow
)
tcp_connecter_t
(
io_thread_
,
this
,
options
,
_addr
,
wait_
);
...
...
src/socks.cpp
View file @
22025872
...
...
@@ -129,6 +129,96 @@ void zmq::socks_choice_decoder_t::reset ()
}
zmq
::
socks_basic_auth_request_t
::
socks_basic_auth_request_t
(
std
::
string
username_
,
std
::
string
password_
)
:
username
(
username_
),
password
(
password_
)
{
zmq_assert
(
username_
.
size
()
<=
UINT8_MAX
);
zmq_assert
(
password_
.
size
()
<=
UINT8_MAX
);
}
zmq
::
socks_basic_auth_request_encoder_t
::
socks_basic_auth_request_encoder_t
()
:
_bytes_encoded
(
0
),
_bytes_written
(
0
)
{
}
void
zmq
::
socks_basic_auth_request_encoder_t
::
encode
(
const
socks_basic_auth_request_t
&
req_
)
{
unsigned
char
*
ptr
=
_buf
;
*
ptr
++
=
0x01
;
*
ptr
++
=
static_cast
<
unsigned
char
>
(
req_
.
username
.
size
());
memcpy
(
ptr
,
req_
.
username
.
c_str
(),
req_
.
username
.
size
());
ptr
+=
req_
.
username
.
size
();
*
ptr
++
=
static_cast
<
unsigned
char
>
(
req_
.
password
.
size
());
memcpy
(
ptr
,
req_
.
password
.
c_str
(),
req_
.
password
.
size
());
ptr
+=
req_
.
password
.
size
();
_bytes_encoded
=
ptr
-
_buf
;
_bytes_written
=
0
;
}
int
zmq
::
socks_basic_auth_request_encoder_t
::
output
(
fd_t
fd_
)
{
const
int
rc
=
tcp_write
(
fd_
,
_buf
+
_bytes_written
,
_bytes_encoded
-
_bytes_written
);
if
(
rc
>
0
)
_bytes_written
+=
static_cast
<
size_t
>
(
rc
);
return
rc
;
}
bool
zmq
::
socks_basic_auth_request_encoder_t
::
has_pending_data
()
const
{
return
_bytes_written
<
_bytes_encoded
;
}
void
zmq
::
socks_basic_auth_request_encoder_t
::
reset
()
{
_bytes_encoded
=
_bytes_written
=
0
;
}
zmq
::
socks_auth_response_t
::
socks_auth_response_t
(
uint8_t
response_code_
)
:
response_code
(
response_code_
)
{
}
zmq
::
socks_auth_response_decoder_t
::
socks_auth_response_decoder_t
()
:
_bytes_read
(
0
)
{
}
int
zmq
::
socks_auth_response_decoder_t
::
input
(
fd_t
fd_
)
{
zmq_assert
(
_bytes_read
<
2
);
const
int
rc
=
tcp_read
(
fd_
,
_buf
+
_bytes_read
,
2
-
_bytes_read
);
if
(
rc
>
0
)
{
_bytes_read
+=
static_cast
<
size_t
>
(
rc
);
if
(
_buf
[
0
]
!=
0x01
)
return
-
1
;
}
return
rc
;
}
bool
zmq
::
socks_auth_response_decoder_t
::
message_ready
()
const
{
return
_bytes_read
==
2
;
}
zmq
::
socks_auth_response_t
zmq
::
socks_auth_response_decoder_t
::
decode
()
{
zmq_assert
(
message_ready
());
return
socks_auth_response_t
(
_buf
[
1
]);
}
void
zmq
::
socks_auth_response_decoder_t
::
reset
()
{
_bytes_read
=
0
;
}
zmq
::
socks_request_t
::
socks_request_t
(
uint8_t
command_
,
std
::
string
hostname_
,
uint16_t
port_
)
:
...
...
src/socks.hpp
View file @
22025872
...
...
@@ -81,6 +81,50 @@ class socks_choice_decoder_t
size_t
_bytes_read
;
};
struct
socks_basic_auth_request_t
{
socks_basic_auth_request_t
(
std
::
string
username_
,
std
::
string
password_
);
const
std
::
string
username
;
const
std
::
string
password
;
};
class
socks_basic_auth_request_encoder_t
{
public
:
socks_basic_auth_request_encoder_t
();
void
encode
(
const
socks_basic_auth_request_t
&
req_
);
int
output
(
fd_t
fd_
);
bool
has_pending_data
()
const
;
void
reset
();
private
:
size_t
_bytes_encoded
;
size_t
_bytes_written
;
uint8_t
_buf
[
1
+
1
+
UINT8_MAX
+
1
+
UINT8_MAX
];
};
struct
socks_auth_response_t
{
socks_auth_response_t
(
uint8_t
response_code_
);
uint8_t
response_code
;
};
class
socks_auth_response_decoder_t
{
public
:
socks_auth_response_decoder_t
();
int
input
(
fd_t
fd_
);
bool
message_ready
()
const
;
socks_auth_response_t
decode
();
void
reset
();
private
:
int8_t
_buf
[
2
];
size_t
_bytes_read
;
};
struct
socks_request_t
{
socks_request_t
(
uint8_t
command_
,
std
::
string
hostname_
,
uint16_t
port_
);
...
...
src/socks_connecter.cpp
View file @
22025872
...
...
@@ -61,6 +61,7 @@ zmq::socks_connecter_t::socks_connecter_t (class io_thread_t *io_thread_,
stream_connecter_base_t
(
io_thread_
,
session_
,
options_
,
addr_
,
delayed_start_
),
_proxy_addr
(
proxy_addr_
),
_auth_method
(
socks_no_auth_required
),
_status
(
unplugged
)
{
zmq_assert
(
_addr
->
protocol
==
protocol_name
::
tcp
);
...
...
@@ -72,8 +73,24 @@ zmq::socks_connecter_t::~socks_connecter_t ()
LIBZMQ_DELETE
(
_proxy_addr
);
}
void
zmq
::
socks_connecter_t
::
set_auth_method_none
()
{
_auth_method
=
socks_no_auth_required
;
_auth_username
.
clear
();
_auth_password
.
clear
();
}
void
zmq
::
socks_connecter_t
::
set_auth_method_basic
(
const
std
::
string
username
,
const
std
::
string
password
)
{
_auth_method
=
socks_basic_auth
;
_auth_username
=
username
;
_auth_password
=
password
;
}
void
zmq
::
socks_connecter_t
::
in_event
()
{
int
expected_status
=
-
1
;
zmq_assert
(
_status
!=
unplugged
);
if
(
_status
==
waiting_for_choice
)
{
...
...
@@ -86,17 +103,21 @@ void zmq::socks_connecter_t::in_event ()
if
(
rc
==
-
1
)
error
();
else
{
std
::
string
hostname
;
uint16_t
port
=
0
;
if
(
parse_address
(
_addr
->
address
,
hostname
,
port
)
==
-
1
)
error
();
else
{
_request_encoder
.
encode
(
socks_request_t
(
1
,
hostname
,
port
));
reset_pollin
(
_handle
);
set_pollout
(
_handle
);
_status
=
sending_request
;
}
if
(
choice
.
method
==
socks_basic_auth
)
expected_status
=
sending_basic_auth_request
;
else
expected_status
=
sending_request
;
}
}
}
else
if
(
_status
==
waiting_for_auth_response
)
{
int
rc
=
_auth_response_decoder
.
input
(
_s
);
if
(
rc
==
0
||
rc
==
-
1
)
error
();
else
if
(
_auth_response_decoder
.
message_ready
())
{
const
socks_auth_response_t
auth_response
=
_auth_response_decoder
.
decode
();
rc
=
process_server_response
(
auth_response
);
if
(
rc
==
-
1
)
error
();
else
{
expected_status
=
sending_request
;
}
}
}
else
if
(
_status
==
waiting_for_response
)
{
...
...
@@ -118,12 +139,33 @@ void zmq::socks_connecter_t::in_event ()
}
}
else
error
();
if
(
expected_status
==
sending_basic_auth_request
)
{
_basic_auth_request_encoder
.
encode
(
socks_basic_auth_request_t
(
_auth_username
,
_auth_password
));
reset_pollin
(
_handle
);
set_pollout
(
_handle
);
_status
=
sending_basic_auth_request
;
}
else
if
(
expected_status
==
sending_request
)
{
std
::
string
hostname
;
uint16_t
port
=
0
;
if
(
parse_address
(
_addr
->
address
,
hostname
,
port
)
==
-
1
)
error
();
else
{
_request_encoder
.
encode
(
socks_request_t
(
1
,
hostname
,
port
));
reset_pollin
(
_handle
);
set_pollout
(
_handle
);
_status
=
sending_request
;
}
}
}
void
zmq
::
socks_connecter_t
::
out_event
()
{
zmq_assert
(
_status
==
waiting_for_proxy_connection
||
_status
==
sending_greeting
||
_status
==
sending_request
);
||
_status
==
sending_greeting
||
_status
==
sending_basic_auth_request
||
_status
==
sending_request
);
if
(
_status
==
waiting_for_proxy_connection
)
{
const
int
rc
=
static_cast
<
int
>
(
check_proxy_connection
());
...
...
@@ -131,7 +173,7 @@ void zmq::socks_connecter_t::out_event ()
error
();
else
{
_greeting_encoder
.
encode
(
socks_greeting_t
(
socks_no_auth_require
d
));
socks_greeting_t
(
_auth_metho
d
));
_status
=
sending_greeting
;
}
}
else
if
(
_status
==
sending_greeting
)
{
...
...
@@ -144,6 +186,16 @@ void zmq::socks_connecter_t::out_event ()
set_pollin
(
_handle
);
_status
=
waiting_for_choice
;
}
}
else
if
(
_status
==
sending_basic_auth_request
)
{
zmq_assert
(
_basic_auth_request_encoder
.
has_pending_data
());
const
int
rc
=
_basic_auth_request_encoder
.
output
(
_s
);
if
(
rc
==
-
1
||
rc
==
0
)
error
();
else
if
(
!
_basic_auth_request_encoder
.
has_pending_data
())
{
reset_pollout
(
_handle
);
set_pollin
(
_handle
);
_status
=
waiting_for_auth_response
;
}
}
else
{
zmq_assert
(
_request_encoder
.
has_pending_data
());
const
int
rc
=
_request_encoder
.
output
(
_s
);
...
...
@@ -189,8 +241,9 @@ void zmq::socks_connecter_t::start_connecting ()
int
zmq
::
socks_connecter_t
::
process_server_response
(
const
socks_choice_t
&
response_
)
{
// We do not support any authentication method for now.
return
response_
.
method
==
0
?
0
:
-
1
;
return
response_
.
method
==
socks_no_auth_required
||
response_
.
method
==
socks_basic_auth
?
0
:
-
1
;
}
int
zmq
::
socks_connecter_t
::
process_server_response
(
...
...
@@ -199,12 +252,20 @@ int zmq::socks_connecter_t::process_server_response (
return
response_
.
response_code
==
0
?
0
:
-
1
;
}
int
zmq
::
socks_connecter_t
::
process_server_response
(
const
socks_auth_response_t
&
response_
)
{
return
response_
.
response_code
==
0
?
0
:
-
1
;
}
void
zmq
::
socks_connecter_t
::
error
()
{
rm_fd
(
_handle
);
close
();
_greeting_encoder
.
reset
();
_choice_decoder
.
reset
();
_basic_auth_request_encoder
.
reset
();
_auth_response_decoder
.
reset
();
_request_encoder
.
reset
();
_response_decoder
.
reset
();
_status
=
unplugged
;
...
...
src/socks_connecter.hpp
View file @
22025872
...
...
@@ -54,6 +54,11 @@ class socks_connecter_t : public stream_connecter_base_t
bool
delayed_start_
);
~
socks_connecter_t
();
void
set_auth_method_basic
(
const
std
::
string
username
,
const
std
::
string
password
);
void
set_auth_method_none
();
private
:
enum
{
...
...
@@ -62,6 +67,8 @@ class socks_connecter_t : public stream_connecter_base_t
waiting_for_proxy_connection
,
sending_greeting
,
waiting_for_choice
,
sending_basic_auth_request
,
waiting_for_auth_response
,
sending_request
,
waiting_for_response
};
...
...
@@ -69,7 +76,9 @@ class socks_connecter_t : public stream_connecter_base_t
// Method ID
enum
{
socks_no_auth_required
=
0
socks_no_auth_required
=
0x00
,
socks_basic_auth
=
0x02
,
socks_no_acceptable_method
=
0xff
};
// Handlers for I/O events.
...
...
@@ -81,6 +90,7 @@ class socks_connecter_t : public stream_connecter_base_t
int
process_server_response
(
const
socks_choice_t
&
response_
);
int
process_server_response
(
const
socks_response_t
&
response_
);
int
process_server_response
(
const
socks_auth_response_t
&
response_
);
int
parse_address
(
const
std
::
string
&
address_
,
std
::
string
&
hostname_
,
...
...
@@ -101,12 +111,21 @@ class socks_connecter_t : public stream_connecter_base_t
socks_greeting_encoder_t
_greeting_encoder
;
socks_choice_decoder_t
_choice_decoder
;
socks_basic_auth_request_encoder_t
_basic_auth_request_encoder
;
socks_auth_response_decoder_t
_auth_response_decoder
;
socks_request_encoder_t
_request_encoder
;
socks_response_decoder_t
_response_decoder
;
// SOCKS address; owned by this connecter.
address_t
*
_proxy_addr
;
// User defined authentication method
int
_auth_method
;
// Credentials for basic authentication
std
::
string
_auth_username
;
std
::
string
_auth_password
;
int
_status
;
socks_connecter_t
(
const
socks_connecter_t
&
);
...
...
src/zmq_draft.h
View file @
22025872
...
...
@@ -53,6 +53,8 @@
#define ZMQ_MULTICAST_LOOP 96
#define ZMQ_ROUTER_NOTIFY 97
#define ZMQ_XPUB_MANUAL_LAST_VALUE 98
#define ZMQ_SOCKS_USERNAME 99
#define ZMQ_SOCKS_PASSWORD 100
/* DRAFT Context options */
#define ZMQ_ZERO_COPY_RECV 10
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment