Coverage Report

Created: 2026-01-17 06:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libzmq/src/socks.cpp
Line
Count
Source
1
/* SPDX-License-Identifier: MPL-2.0 */
2
3
#include "precompiled.hpp"
4
#include <sys/types.h>
5
6
#include "err.hpp"
7
#include "socks.hpp"
8
#include "tcp.hpp"
9
#include "blob.hpp"
10
11
#ifndef ZMQ_HAVE_WINDOWS
12
#include <sys/socket.h>
13
#include <netinet/in.h>
14
#include <netdb.h>
15
#endif
16
17
0
zmq::socks_greeting_t::socks_greeting_t (uint8_t method_) : num_methods (1)
18
0
{
19
0
    methods[0] = method_;
20
0
}
21
22
zmq::socks_greeting_t::socks_greeting_t (const uint8_t *methods_,
23
                                         uint8_t num_methods_) :
24
0
    num_methods (num_methods_)
25
0
{
26
0
    for (uint8_t i = 0; i < num_methods_; i++)
27
0
        methods[i] = methods_[i];
28
0
}
29
30
zmq::socks_greeting_encoder_t::socks_greeting_encoder_t () :
31
0
    _bytes_encoded (0), _bytes_written (0)
32
0
{
33
0
}
34
35
void zmq::socks_greeting_encoder_t::encode (const socks_greeting_t &greeting_)
36
0
{
37
0
    uint8_t *ptr = _buf;
38
39
0
    *ptr++ = 0x05;
40
0
    *ptr++ = static_cast<uint8_t> (greeting_.num_methods);
41
0
    for (uint8_t i = 0; i < greeting_.num_methods; i++)
42
0
        *ptr++ = greeting_.methods[i];
43
44
0
    _bytes_encoded = 2 + greeting_.num_methods;
45
0
    _bytes_written = 0;
46
0
}
47
48
int zmq::socks_greeting_encoder_t::output (fd_t fd_)
49
0
{
50
0
    const int rc =
51
0
      tcp_write (fd_, _buf + _bytes_written, _bytes_encoded - _bytes_written);
52
0
    if (rc > 0)
53
0
        _bytes_written += static_cast<size_t> (rc);
54
0
    return rc;
55
0
}
56
57
bool zmq::socks_greeting_encoder_t::has_pending_data () const
58
0
{
59
0
    return _bytes_written < _bytes_encoded;
60
0
}
61
62
void zmq::socks_greeting_encoder_t::reset ()
63
0
{
64
0
    _bytes_encoded = _bytes_written = 0;
65
0
}
66
67
0
zmq::socks_choice_t::socks_choice_t (unsigned char method_) : method (method_)
68
0
{
69
0
}
70
71
0
zmq::socks_choice_decoder_t::socks_choice_decoder_t () : _bytes_read (0)
72
0
{
73
0
}
74
75
int zmq::socks_choice_decoder_t::input (fd_t fd_)
76
0
{
77
0
    zmq_assert (_bytes_read < 2);
78
0
    const int rc = tcp_read (fd_, _buf + _bytes_read, 2 - _bytes_read);
79
0
    if (rc > 0) {
80
0
        _bytes_read += static_cast<size_t> (rc);
81
0
        if (_buf[0] != 0x05)
82
0
            return -1;
83
0
    }
84
0
    return rc;
85
0
}
86
87
bool zmq::socks_choice_decoder_t::message_ready () const
88
0
{
89
0
    return _bytes_read == 2;
90
0
}
91
92
zmq::socks_choice_t zmq::socks_choice_decoder_t::decode ()
93
0
{
94
0
    zmq_assert (message_ready ());
95
0
    return socks_choice_t (_buf[1]);
96
0
}
97
98
void zmq::socks_choice_decoder_t::reset ()
99
0
{
100
0
    _bytes_read = 0;
101
0
}
102
103
104
zmq::socks_basic_auth_request_t::socks_basic_auth_request_t (
105
  const std::string &username_, const std::string &password_) :
106
0
    username (username_), password (password_)
107
0
{
108
0
    zmq_assert (username_.size () <= UINT8_MAX);
109
0
    zmq_assert (password_.size () <= UINT8_MAX);
110
0
}
111
112
113
zmq::socks_basic_auth_request_encoder_t::socks_basic_auth_request_encoder_t () :
114
0
    _bytes_encoded (0), _bytes_written (0)
115
0
{
116
0
}
117
118
void zmq::socks_basic_auth_request_encoder_t::encode (
119
  const socks_basic_auth_request_t &req_)
120
0
{
121
0
    unsigned char *ptr = _buf;
122
0
    *ptr++ = 0x01;
123
0
    *ptr++ = static_cast<unsigned char> (req_.username.size ());
124
0
    memcpy (ptr, req_.username.c_str (), req_.username.size ());
125
0
    ptr += req_.username.size ();
126
0
    *ptr++ = static_cast<unsigned char> (req_.password.size ());
127
0
    memcpy (ptr, req_.password.c_str (), req_.password.size ());
128
0
    ptr += req_.password.size ();
129
130
0
    _bytes_encoded = ptr - _buf;
131
0
    _bytes_written = 0;
132
0
}
133
134
int zmq::socks_basic_auth_request_encoder_t::output (fd_t fd_)
135
0
{
136
0
    const int rc =
137
0
      tcp_write (fd_, _buf + _bytes_written, _bytes_encoded - _bytes_written);
138
0
    if (rc > 0)
139
0
        _bytes_written += static_cast<size_t> (rc);
140
0
    return rc;
141
0
}
142
143
bool zmq::socks_basic_auth_request_encoder_t::has_pending_data () const
144
0
{
145
0
    return _bytes_written < _bytes_encoded;
146
0
}
147
148
void zmq::socks_basic_auth_request_encoder_t::reset ()
149
0
{
150
0
    _bytes_encoded = _bytes_written = 0;
151
0
}
152
153
154
zmq::socks_auth_response_t::socks_auth_response_t (uint8_t response_code_) :
155
0
    response_code (response_code_)
156
0
{
157
0
}
158
159
zmq::socks_auth_response_decoder_t::socks_auth_response_decoder_t () :
160
0
    _bytes_read (0)
161
0
{
162
0
}
163
164
int zmq::socks_auth_response_decoder_t::input (fd_t fd_)
165
0
{
166
0
    zmq_assert (_bytes_read < 2);
167
0
    const int rc = tcp_read (fd_, _buf + _bytes_read, 2 - _bytes_read);
168
0
    if (rc > 0) {
169
0
        _bytes_read += static_cast<size_t> (rc);
170
0
        if (_buf[0] != 0x01)
171
0
            return -1;
172
0
    }
173
0
    return rc;
174
0
}
175
176
bool zmq::socks_auth_response_decoder_t::message_ready () const
177
0
{
178
0
    return _bytes_read == 2;
179
0
}
180
181
zmq::socks_auth_response_t zmq::socks_auth_response_decoder_t::decode ()
182
0
{
183
0
    zmq_assert (message_ready ());
184
0
    return socks_auth_response_t (_buf[1]);
185
0
}
186
187
void zmq::socks_auth_response_decoder_t::reset ()
188
0
{
189
0
    _bytes_read = 0;
190
0
}
191
192
193
zmq::socks_request_t::socks_request_t (uint8_t command_,
194
                                       std::string hostname_,
195
                                       uint16_t port_) :
196
0
    command (command_), hostname (ZMQ_MOVE (hostname_)), port (port_)
197
0
{
198
0
    zmq_assert (hostname.size () <= UINT8_MAX);
199
0
}
200
201
zmq::socks_request_encoder_t::socks_request_encoder_t () :
202
0
    _bytes_encoded (0), _bytes_written (0)
203
0
{
204
0
}
205
206
void zmq::socks_request_encoder_t::encode (const socks_request_t &req_)
207
0
{
208
0
    zmq_assert (req_.hostname.size () <= UINT8_MAX);
209
210
0
    unsigned char *ptr = _buf;
211
0
    *ptr++ = 0x05;
212
0
    *ptr++ = req_.command;
213
0
    *ptr++ = 0x00;
214
215
#if defined ZMQ_HAVE_OPENVMS && defined __ia64 && __INITIAL_POINTER_SIZE == 64
216
    __addrinfo64 hints, *res = NULL;
217
#else
218
0
    addrinfo hints, *res = NULL;
219
0
#endif
220
221
0
    memset (&hints, 0, sizeof hints);
222
223
    //  Suppress potential DNS lookups.
224
0
    hints.ai_flags = AI_NUMERICHOST;
225
226
0
    const int rc = getaddrinfo (req_.hostname.c_str (), NULL, &hints, &res);
227
0
    if (rc == 0 && res->ai_family == AF_INET) {
228
0
        const struct sockaddr_in *sockaddr_in =
229
0
          reinterpret_cast<const struct sockaddr_in *> (res->ai_addr);
230
0
        *ptr++ = 0x01;
231
0
        memcpy (ptr, &sockaddr_in->sin_addr, 4);
232
0
        ptr += 4;
233
0
    } else if (rc == 0 && res->ai_family == AF_INET6) {
234
0
        const struct sockaddr_in6 *sockaddr_in6 =
235
0
          reinterpret_cast<const struct sockaddr_in6 *> (res->ai_addr);
236
0
        *ptr++ = 0x04;
237
0
        memcpy (ptr, &sockaddr_in6->sin6_addr, 16);
238
0
        ptr += 16;
239
0
    } else {
240
0
        *ptr++ = 0x03;
241
0
        *ptr++ = static_cast<unsigned char> (req_.hostname.size ());
242
0
        memcpy (ptr, req_.hostname.c_str (), req_.hostname.size ());
243
0
        ptr += req_.hostname.size ();
244
0
    }
245
246
0
    if (rc == 0)
247
0
        freeaddrinfo (res);
248
249
0
    *ptr++ = req_.port / 256;
250
0
    *ptr++ = req_.port % 256;
251
252
0
    _bytes_encoded = ptr - _buf;
253
0
    _bytes_written = 0;
254
0
}
255
256
int zmq::socks_request_encoder_t::output (fd_t fd_)
257
0
{
258
0
    const int rc =
259
0
      tcp_write (fd_, _buf + _bytes_written, _bytes_encoded - _bytes_written);
260
0
    if (rc > 0)
261
0
        _bytes_written += static_cast<size_t> (rc);
262
0
    return rc;
263
0
}
264
265
bool zmq::socks_request_encoder_t::has_pending_data () const
266
0
{
267
0
    return _bytes_written < _bytes_encoded;
268
0
}
269
270
void zmq::socks_request_encoder_t::reset ()
271
0
{
272
0
    _bytes_encoded = _bytes_written = 0;
273
0
}
274
275
zmq::socks_response_t::socks_response_t (uint8_t response_code_,
276
                                         const std::string &address_,
277
                                         uint16_t port_) :
278
0
    response_code (response_code_), address (address_), port (port_)
279
0
{
280
0
}
281
282
0
zmq::socks_response_decoder_t::socks_response_decoder_t () : _bytes_read (0)
283
0
{
284
0
}
285
286
int zmq::socks_response_decoder_t::input (fd_t fd_)
287
0
{
288
0
    size_t n = 0;
289
290
0
    if (_bytes_read < 5)
291
0
        n = 5 - _bytes_read;
292
0
    else {
293
0
        const uint8_t atyp = _buf[3];
294
0
        zmq_assert (atyp == 0x01 || atyp == 0x03 || atyp == 0x04);
295
0
        if (atyp == 0x01)
296
0
            n = 3 + 2;
297
0
        else if (atyp == 0x03)
298
0
            n = _buf[4] + 2;
299
0
        else if (atyp == 0x04)
300
0
            n = 15 + 2;
301
0
    }
302
0
    const int rc = tcp_read (fd_, _buf + _bytes_read, n);
303
0
    if (rc > 0) {
304
0
        _bytes_read += static_cast<size_t> (rc);
305
0
        if (_buf[0] != 0x05)
306
0
            return -1;
307
0
        if (_bytes_read >= 2)
308
0
            if (_buf[1] > 0x08)
309
0
                return -1;
310
0
        if (_bytes_read >= 3)
311
0
            if (_buf[2] != 0x00)
312
0
                return -1;
313
0
        if (_bytes_read >= 4) {
314
0
            const uint8_t atyp = _buf[3];
315
0
            if (atyp != 0x01 && atyp != 0x03 && atyp != 0x04)
316
0
                return -1;
317
0
        }
318
0
    }
319
0
    return rc;
320
0
}
321
322
bool zmq::socks_response_decoder_t::message_ready () const
323
0
{
324
0
    if (_bytes_read < 4)
325
0
        return false;
326
327
0
    const uint8_t atyp = _buf[3];
328
0
    zmq_assert (atyp == 0x01 || atyp == 0x03 || atyp == 0x04);
329
0
    if (atyp == 0x01)
330
0
        return _bytes_read == 10;
331
0
    if (atyp == 0x03)
332
0
        return _bytes_read > 4 && _bytes_read == 4 + 1 + _buf[4] + 2u;
333
334
0
    return _bytes_read == 22;
335
0
}
336
337
zmq::socks_response_t zmq::socks_response_decoder_t::decode ()
338
0
{
339
0
    zmq_assert (message_ready ());
340
0
    return socks_response_t (_buf[1], "", 0);
341
0
}
342
343
void zmq::socks_response_decoder_t::reset ()
344
0
{
345
0
    _bytes_read = 0;
346
0
}