socks.cpp 7.74 KB
Newer Older
1
/*
2
    Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
3

4
    This file is part of libzmq, the ZeroMQ core engine in C++.
5

6 7 8
    libzmq is free software; you can redistribute it and/or modify it under
    the terms of the GNU Lesser General Public License (LGPL) as published
    by the Free Software Foundation; either version 3 of the License, or
9 10
    (at your option) any later version.

11 12 13 14 15 16 17 18 19 20 21 22 23 24
    As a special exception, the Contributors give you permission to link
    this library with independent modules to produce an executable,
    regardless of the license terms of these independent modules, and to
    copy and distribute the resulting executable under terms of your choice,
    provided that you also meet, for each linked independent module, the
    terms and conditions of the license of that module. An independent
    module is a module which is not derived from or based on this library.
    If you modify this library, you must extend this exception to your
    version of the library.

    libzmq is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
    License for more details.
25 26 27 28 29

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

30
#include "precompiled.hpp"
31 32 33 34 35 36
#include <sys/types.h>

#include "err.hpp"
#include "socks.hpp"
#include "tcp.hpp"

Richard Newton's avatar
Richard Newton committed
37 38
#ifndef ZMQ_HAVE_WINDOWS
#include <sys/socket.h>
39
#include <netinet/in.h>
Richard Newton's avatar
Richard Newton committed
40 41 42
#include <netdb.h>
#endif

43
zmq::socks_greeting_t::socks_greeting_t (uint8_t method_) : num_methods (1)
44
{
45
    methods[0] = method_;
46 47
}

48 49 50
zmq::socks_greeting_t::socks_greeting_t (uint8_t *methods_,
                                         uint8_t num_methods_) :
    num_methods (num_methods_)
51
{
52
    for (uint8_t i = 0; i < num_methods_; i++)
53
        methods[i] = methods_[i];
54 55
}

56
zmq::socks_greeting_encoder_t::socks_greeting_encoder_t () :
57 58
    _bytes_encoded (0),
    _bytes_written (0)
59 60
{
}
61 62 63

void zmq::socks_greeting_encoder_t::encode (const socks_greeting_t &greeting_)
{
64
    uint8_t *ptr = _buf;
65 66

    *ptr++ = 0x05;
67
    *ptr++ = static_cast<uint8_t> (greeting_.num_methods);
68
    for (uint8_t i = 0; i < greeting_.num_methods; i++)
69
        *ptr++ = greeting_.methods[i];
70

71 72
    _bytes_encoded = 2 + greeting_.num_methods;
    _bytes_written = 0;
73 74 75 76
}

int zmq::socks_greeting_encoder_t::output (fd_t fd_)
{
77
    const int rc =
78
      tcp_write (fd_, _buf + _bytes_written, _bytes_encoded - _bytes_written);
79
    if (rc > 0)
80
        _bytes_written += static_cast<size_t> (rc);
81 82 83 84 85
    return rc;
}

bool zmq::socks_greeting_encoder_t::has_pending_data () const
{
86
    return _bytes_written < _bytes_encoded;
87 88 89 90
}

void zmq::socks_greeting_encoder_t::reset ()
{
91
    _bytes_encoded = _bytes_written = 0;
92 93
}

94 95 96
zmq::socks_choice_t::socks_choice_t (unsigned char method_) : method (method_)
{
}
97

98
zmq::socks_choice_decoder_t::socks_choice_decoder_t () : _bytes_read (0)
99 100
{
}
101 102 103

int zmq::socks_choice_decoder_t::input (fd_t fd_)
{
104 105
    zmq_assert (_bytes_read < 2);
    const int rc = tcp_read (fd_, _buf + _bytes_read, 2 - _bytes_read);
106
    if (rc > 0) {
107 108
        _bytes_read += static_cast<size_t> (rc);
        if (_buf[0] != 0x05)
109 110 111 112 113 114 115
            return -1;
    }
    return rc;
}

bool zmq::socks_choice_decoder_t::message_ready () const
{
116
    return _bytes_read == 2;
117 118 119 120 121
}

zmq::socks_choice_t zmq::socks_choice_decoder_t::decode ()
{
    zmq_assert (message_ready ());
122
    return socks_choice_t (_buf[1]);
123 124 125 126
}

void zmq::socks_choice_decoder_t::reset ()
{
127
    _bytes_read = 0;
128 129
}

130

131 132 133 134 135 136
zmq::socks_request_t::socks_request_t (uint8_t command_,
                                       std::string hostname_,
                                       uint16_t port_) :
    command (command_),
    hostname (hostname_),
    port (port_)
137 138 139
{
    zmq_assert (hostname_.size () <= UINT8_MAX);
}
140

141
zmq::socks_request_encoder_t::socks_request_encoder_t () :
142 143
    _bytes_encoded (0),
    _bytes_written (0)
144 145
{
}
146

147
void zmq::socks_request_encoder_t::encode (const socks_request_t &req_)
148
{
149
    zmq_assert (req_.hostname.size () <= UINT8_MAX);
150

151
    unsigned char *ptr = _buf;
152
    *ptr++ = 0x05;
153
    *ptr++ = req_.command;
154 155 156 157 158 159 160 161 162 163 164 165 166
    *ptr++ = 0x00;

#if defined ZMQ_HAVE_OPENVMS && defined __ia64 && __INITIAL_POINTER_SIZE == 64
    __addrinfo64 hints, *res = NULL;
#else
    addrinfo hints, *res = NULL;
#endif

    memset (&hints, 0, sizeof hints);

    //  Suppress potential DNS lookups.
    hints.ai_flags = AI_NUMERICHOST;

167
    const int rc = getaddrinfo (req_.hostname.c_str (), NULL, &hints, &res);
168
    if (rc == 0 && res->ai_family == AF_INET) {
169 170
        const struct sockaddr_in *sockaddr_in =
          reinterpret_cast<const struct sockaddr_in *> (res->ai_addr);
171 172 173
        *ptr++ = 0x01;
        memcpy (ptr, &sockaddr_in->sin_addr, 4);
        ptr += 4;
174
    } else if (rc == 0 && res->ai_family == AF_INET6) {
175 176
        const struct sockaddr_in6 *sockaddr_in6 =
          reinterpret_cast<const struct sockaddr_in6 *> (res->ai_addr);
177 178 179
        *ptr++ = 0x04;
        memcpy (ptr, &sockaddr_in6->sin6_addr, 16);
        ptr += 16;
180
    } else {
181
        *ptr++ = 0x03;
182 183 184
        *ptr++ = static_cast<unsigned char> (req_.hostname.size ());
        memcpy (ptr, req_.hostname.c_str (), req_.hostname.size ());
        ptr += req_.hostname.size ();
185 186 187 188 189
    }

    if (rc == 0)
        freeaddrinfo (res);

190 191
    *ptr++ = req_.port / 256;
    *ptr++ = req_.port % 256;
192

193 194
    _bytes_encoded = ptr - _buf;
    _bytes_written = 0;
195 196 197 198
}

int zmq::socks_request_encoder_t::output (fd_t fd_)
{
199
    const int rc =
200
      tcp_write (fd_, _buf + _bytes_written, _bytes_encoded - _bytes_written);
201
    if (rc > 0)
202
        _bytes_written += static_cast<size_t> (rc);
203 204 205 206 207
    return rc;
}

bool zmq::socks_request_encoder_t::has_pending_data () const
{
208
    return _bytes_written < _bytes_encoded;
209 210 211 212
}

void zmq::socks_request_encoder_t::reset ()
{
213
    _bytes_encoded = _bytes_written = 0;
214 215
}

216 217 218 219 220 221 222 223
zmq::socks_response_t::socks_response_t (uint8_t response_code_,
                                         std::string address_,
                                         uint16_t port_) :
    response_code (response_code_),
    address (address_),
    port (port_)
{
}
224

225
zmq::socks_response_decoder_t::socks_response_decoder_t () : _bytes_read (0)
226 227
{
}
228 229 230 231 232

int zmq::socks_response_decoder_t::input (fd_t fd_)
{
    size_t n = 0;

233 234
    if (_bytes_read < 5)
        n = 5 - _bytes_read;
235
    else {
236
        const uint8_t atyp = _buf[3];
237 238 239
        zmq_assert (atyp == 0x01 || atyp == 0x03 || atyp == 0x04);
        if (atyp == 0x01)
            n = 3 + 2;
240
        else if (atyp == 0x03)
241
            n = _buf[4] + 2;
242
        else if (atyp == 0x04)
243 244
            n = 15 + 2;
    }
245
    const int rc = tcp_read (fd_, _buf + _bytes_read, n);
246
    if (rc > 0) {
247 248
        _bytes_read += static_cast<size_t> (rc);
        if (_buf[0] != 0x05)
249
            return -1;
250 251
        if (_bytes_read >= 2)
            if (_buf[1] > 0x08)
252
                return -1;
253 254
        if (_bytes_read >= 3)
            if (_buf[2] != 0x00)
255
                return -1;
256 257
        if (_bytes_read >= 4) {
            const uint8_t atyp = _buf[3];
258 259 260 261 262 263 264 265 266
            if (atyp != 0x01 && atyp != 0x03 && atyp != 0x04)
                return -1;
        }
    }
    return rc;
}

bool zmq::socks_response_decoder_t::message_ready () const
{
267
    if (_bytes_read < 4)
268
        return false;
269

270
    const uint8_t atyp = _buf[3];
271 272
    zmq_assert (atyp == 0x01 || atyp == 0x03 || atyp == 0x04);
    if (atyp == 0x01)
273
        return _bytes_read == 10;
274
    if (atyp == 0x03)
275
        return _bytes_read > 4 && _bytes_read == 4 + 1 + _buf[4] + 2u;
276
    else
277
        return _bytes_read == 22;
278 279 280 281 282
}

zmq::socks_response_t zmq::socks_response_decoder_t::decode ()
{
    zmq_assert (message_ready ());
283
    return socks_response_t (_buf[1], "", 0);
284 285 286 287
}

void zmq::socks_response_decoder_t::reset ()
{
288
    _bytes_read = 0;
289
}