libzmq  master
ZeroMQ C++ Core Engine (LIBZMQ)
socks.cpp
Go to the documentation of this file.
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  libzmq is free software; you can redistribute it and/or modify it under
7  the terms of the GNU Lesser General Public License (LGPL) as published
8  by the Free Software Foundation; either version 3 of the License, or
9  (at your option) any later version.
10 
11  As a special exception, the Contributors give you permission to link
12  this library with independent modules to produce an executable,
13  regardless of the license terms of these independent modules, and to
14  copy and distribute the resulting executable under terms of your choice,
15  provided that you also meet, for each linked independent module, the
16  terms and conditions of the license of that module. An independent
17  module is a module which is not derived from or based on this library.
18  If you modify this library, you must extend this exception to your
19  version of the library.
20 
21  libzmq is distributed in the hope that it will be useful, but WITHOUT
22  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
24  License for more details.
25 
26  You should have received a copy of the GNU Lesser General Public License
27  along with this program. If not, see <http://www.gnu.org/licenses/>.
28 */
29 
30 #include "precompiled.hpp"
31 #include <sys/types.h>
32 
33 #include "err.hpp"
34 #include "platform.hpp"
35 #include "socks.hpp"
36 #include "tcp.hpp"
37 
38 #ifndef ZMQ_HAVE_WINDOWS
39 #include <sys/socket.h>
40 #include <netinet/in.h>
41 #include <netdb.h>
42 #endif
43 
45  num_methods (1)
46 {
47  methods [0] = method_;
48 }
49 
51  uint8_t *methods_, uint8_t num_methods_)
52  : num_methods (num_methods_)
53 {
54  for (uint8_t i = 0; i < num_methods_; i++)
55  methods [i] = methods_ [i];
56 }
57 
59  : bytes_encoded (0), bytes_written (0)
60 {}
61 
63 {
64  uint8_t *ptr = buf;
65 
66  *ptr++ = 0x05;
67  *ptr++ = (uint8_t) greeting_.num_methods;
68  for (uint8_t i = 0; i < greeting_.num_methods; i++)
69  *ptr++ = greeting_.methods [i];
70 
71  bytes_encoded = 2 + greeting_.num_methods;
72  bytes_written = 0;
73 }
74 
76 {
77  const int rc = tcp_write (
79  if (rc > 0)
80  bytes_written += static_cast <size_t> (rc);
81  return rc;
82 }
83 
85 {
87 }
88 
90 {
92 }
93 
94 zmq::socks_choice_t::socks_choice_t (unsigned char method_)
95  : method (method_)
96 {}
97 
99  : bytes_read (0)
100 {}
101 
103 {
104  zmq_assert (bytes_read < 2);
105  const int rc = tcp_read (fd_, buf + bytes_read, 2 - bytes_read);
106  if (rc > 0) {
107  bytes_read += static_cast <size_t> (rc);
108  if (buf [0] != 0x05)
109  return -1;
110  }
111  return rc;
112 }
113 
115 {
116  return bytes_read == 2;
117 }
118 
120 {
122  return socks_choice_t (buf [1]);
123 }
124 
126 {
127  bytes_read = 0;
128 }
129 
130 
132  uint8_t command_, std::string hostname_, uint16_t port_)
133  : command (command_), hostname (hostname_), port (port_)
134 {
135  zmq_assert (hostname_.size () <= UINT8_MAX);
136 }
137 
139  : bytes_encoded (0), bytes_written (0)
140 {}
141 
143 {
144  zmq_assert (req.hostname.size() <= UINT8_MAX);
145 
146  unsigned char *ptr = buf;
147  *ptr++ = 0x05;
148  *ptr++ = req.command;
149  *ptr++ = 0x00;
150 
151 #if defined ZMQ_HAVE_OPENVMS && defined __ia64 && __INITIAL_POINTER_SIZE == 64
152  __addrinfo64 hints, *res = NULL;
153 #else
154  addrinfo hints, *res = NULL;
155 #endif
156 
157  memset (&hints, 0, sizeof hints);
158 
159  // Suppress potential DNS lookups.
160  hints.ai_flags = AI_NUMERICHOST;
161 
162  const int rc = getaddrinfo (req.hostname.c_str (), NULL, &hints, &res);
163  if (rc == 0 && res->ai_family == AF_INET) {
164  struct sockaddr_in *sockaddr_in =
165  reinterpret_cast <struct sockaddr_in *> (res->ai_addr);
166  *ptr++ = 0x01;
167  memcpy (ptr, &sockaddr_in->sin_addr, 4);
168  ptr += 4;
169  }
170  else
171  if (rc == 0 && res->ai_family == AF_INET6) {
172  struct sockaddr_in6 *sockaddr_in6 =
173  reinterpret_cast <struct sockaddr_in6 *> (res->ai_addr);
174  *ptr++ = 0x04;
175  memcpy (ptr, &sockaddr_in6->sin6_addr, 16);
176  ptr += 16;
177  }
178  else {
179  *ptr++ = 0x03;
180  *ptr++ = (unsigned char) req.hostname.size ();
181  memcpy (ptr, req.hostname.c_str (), req.hostname.size ());
182  ptr += req.hostname.size ();
183  }
184 
185  if (rc == 0)
186  freeaddrinfo (res);
187 
188  *ptr++ = req.port / 256;
189  *ptr++ = req.port % 256;
190 
191  bytes_encoded = ptr - buf;
192  bytes_written = 0;
193 }
194 
196 {
197  const int rc = tcp_write (
199  if (rc > 0)
200  bytes_written += static_cast <size_t> (rc);
201  return rc;
202 }
203 
205 {
206  return bytes_written < bytes_encoded;
207 }
208 
210 {
212 }
213 
215  uint8_t response_code_, std::string address_, uint16_t port_)
216  : response_code (response_code_), address (address_), port (port_)
217 {}
218 
220  : bytes_read (0)
221 {}
222 
224 {
225  size_t n = 0;
226 
227  if (bytes_read < 5)
228  n = 5 - bytes_read;
229  else {
230  const uint8_t atyp = buf [3];
231  zmq_assert (atyp == 0x01 || atyp == 0x03 || atyp == 0x04);
232  if (atyp == 0x01)
233  n = 3 + 2;
234  else
235  if (atyp == 0x03)
236  n = buf [4] + 2;
237  else
238  if (atyp == 0x04)
239  n = 15 + 2;
240  }
241  const int rc = tcp_read (fd_, buf + bytes_read, n);
242  if (rc > 0) {
243  bytes_read += static_cast <size_t> (rc);
244  if (buf [0] != 0x05)
245  return -1;
246  if (bytes_read >= 2)
247  if (buf [1] > 0x08)
248  return -1;
249  if (bytes_read >= 3)
250  if (buf [2] != 0x00)
251  return -1;
252  if (bytes_read >= 4) {
253  const uint8_t atyp = buf [3];
254  if (atyp != 0x01 && atyp != 0x03 && atyp != 0x04)
255  return -1;
256  }
257  }
258  return rc;
259 }
260 
262 {
263  if (bytes_read < 4)
264  return false;
265  else {
266  const uint8_t atyp = buf [3];
267  zmq_assert (atyp == 0x01 || atyp == 0x03 || atyp == 0x04);
268  if (atyp == 0x01)
269  return bytes_read == 10;
270  else
271  if (atyp == 0x03)
272  return bytes_read > 4 && bytes_read == 4 + 1 + buf [4] + 2u;
273  else
274  return bytes_read == 22;
275  }
276 }
277 
279 {
281  return socks_response_t (buf [1], "", 0);
282 }
283 
285 {
286  bytes_read = 0;
287 }
void encode(const socks_request_t &req)
Definition: socks.cpp:142
const uint8_t command
Definition: socks.hpp:90
const size_t num_methods
Definition: socks.hpp:46
bool message_ready() const
Definition: socks.cpp:261
#define zmq_assert(x)
Definition: err.hpp:119
int8_t buf[4+UINT8_MAX+1+2]
Definition: socks.hpp:129
bool has_pending_data() const
Definition: socks.cpp:84
uint8_t buf[4+UINT8_MAX+1+2]
Definition: socks.hpp:107
unsigned char buf[2]
Definition: socks.hpp:81
bool message_ready() const
Definition: socks.cpp:114
socks_choice_t decode()
Definition: socks.cpp:119
void encode(const socks_greeting_t &greeting_)
Definition: socks.cpp:62
int tcp_write(fd_t s_, const void *data_, size_t size_)
Definition: tcp.cpp:187
socks_choice_t(uint8_t method_)
Definition: socks.cpp:94
const uint16_t port
Definition: socks.hpp:92
bool has_pending_data() const
Definition: socks.cpp:204
#define UINT8_MAX
Definition: stdint.hpp:73
socks_request_t(uint8_t command_, std::string hostname_, uint16_t port_)
Definition: socks.cpp:131
uint8_t buf[2+UINT8_MAX]
Definition: socks.hpp:61
const char * address
Definition: test_fork.cpp:32
uint8_t methods[UINT8_MAX]
Definition: socks.hpp:45
socks_greeting_t(uint8_t method)
Definition: socks.cpp:44
int tcp_read(fd_t s_, void *data_, size_t size_)
Definition: tcp.cpp:248
socks_response_t(uint8_t response_code_, std::string address_, uint16_t port_)
Definition: socks.cpp:214
socks_response_t decode()
Definition: socks.cpp:278
const std::string hostname
Definition: socks.hpp:91