tcp_address.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: MPL-2.0 */
2 
3 #include "precompiled.hpp"
4 #include <string>
5 
6 #include "macros.hpp"
7 #include "tcp_address.hpp"
8 #include "stdint.hpp"
9 #include "err.hpp"
10 #include "ip.hpp"
11 
12 #ifndef ZMQ_HAVE_WINDOWS
13 #include <sys/types.h>
14 #include <arpa/inet.h>
15 #include <netinet/tcp.h>
16 #include <net/if.h>
17 #include <netdb.h>
18 #include <ctype.h>
19 #include <unistd.h>
20 #include <stdlib.h>
21 #endif
22 
23 #include <limits.h>
24 
26 {
27  memset (&_address, 0, sizeof (_address));
28  memset (&_source_address, 0, sizeof (_source_address));
29 }
30 
31 zmq::tcp_address_t::tcp_address_t (const sockaddr *sa_, socklen_t sa_len_) :
32  _has_src_addr (false)
33 {
34  zmq_assert (sa_ && sa_len_ > 0);
35 
36  memset (&_address, 0, sizeof (_address));
37  memset (&_source_address, 0, sizeof (_source_address));
38  if (sa_->sa_family == AF_INET
39  && sa_len_ >= static_cast<socklen_t> (sizeof (_address.ipv4)))
40  memcpy (&_address.ipv4, sa_, sizeof (_address.ipv4));
41  else if (sa_->sa_family == AF_INET6
42  && sa_len_ >= static_cast<socklen_t> (sizeof (_address.ipv6)))
43  memcpy (&_address.ipv6, sa_, sizeof (_address.ipv6));
44 }
45 
46 int zmq::tcp_address_t::resolve (const char *name_, bool local_, bool ipv6_)
47 {
48  // Test the ';' to know if we have a source address in name_
49  const char *src_delimiter = strrchr (name_, ';');
50  if (src_delimiter) {
51  const std::string src_name (name_, src_delimiter - name_);
52 
53  ip_resolver_options_t src_resolver_opts;
54 
55  src_resolver_opts
56  .bindable (true)
57  // Restrict hostname/service to literals to avoid any DNS
58  // lookups or service-name irregularity due to
59  // indeterminate socktype.
60  .allow_dns (false)
61  .allow_nic_name (true)
62  .ipv6 (ipv6_)
63  .expect_port (true);
64 
65  ip_resolver_t src_resolver (src_resolver_opts);
66 
67  const int rc =
68  src_resolver.resolve (&_source_address, src_name.c_str ());
69  if (rc != 0)
70  return -1;
71  name_ = src_delimiter + 1;
72  _has_src_addr = true;
73  }
74 
75  ip_resolver_options_t resolver_opts;
76 
77  resolver_opts.bindable (local_)
78  .allow_dns (true)
79  .allow_nic_name (local_)
80  .ipv6 (ipv6_)
81  .expect_port (true);
82 
83  ip_resolver_t resolver (resolver_opts);
84 
85  return resolver.resolve (&_address, name_);
86 }
87 
88 template <size_t N1, size_t N2>
89 static std::string make_address_string (const char *hbuf_,
90  uint16_t port_,
91  const char (&ipv6_prefix_)[N1],
92  const char (&ipv6_suffix_)[N2])
93 {
94  const size_t max_port_str_length = 5;
95  char buf[NI_MAXHOST + sizeof ipv6_prefix_ + sizeof ipv6_suffix_
96  + max_port_str_length];
97  char *pos = buf;
98  memcpy (pos, ipv6_prefix_, sizeof ipv6_prefix_ - 1);
99  pos += sizeof ipv6_prefix_ - 1;
100  const size_t hbuf_len = strlen (hbuf_);
101  memcpy (pos, hbuf_, hbuf_len);
102  pos += hbuf_len;
103  memcpy (pos, ipv6_suffix_, sizeof ipv6_suffix_ - 1);
104  pos += sizeof ipv6_suffix_ - 1;
105  int res = snprintf (pos, max_port_str_length + 1, "%d", ntohs (port_));
106  zmq_assert (res > 0 && res < (int) (max_port_str_length + 1));
107  pos += res;
108  return std::string (buf, pos - buf);
109 }
110 
112 {
113  if (_address.family () != AF_INET && _address.family () != AF_INET6) {
114  addr_.clear ();
115  return -1;
116  }
117 
118  // Not using service resolving because of
119  // https://github.com/zeromq/libzmq/commit/1824574f9b5a8ce786853320e3ea09fe1f822bc4
120  char hbuf[NI_MAXHOST];
121  const int rc = getnameinfo (addr (), addrlen (), hbuf, sizeof (hbuf), NULL,
122  0, NI_NUMERICHOST);
123  if (rc != 0) {
124  addr_.clear ();
125  return rc;
126  }
127 
128  const char ipv4_prefix[] = "tcp://";
129  const char ipv4_suffix[] = ":";
130  const char ipv6_prefix[] = "tcp://[";
131  const char ipv6_suffix[] = "]:";
132  if (_address.family () == AF_INET6) {
133  addr_ = make_address_string (hbuf, _address.ipv6.sin6_port, ipv6_prefix,
134  ipv6_suffix);
135  } else {
136  addr_ = make_address_string (hbuf, _address.ipv4.sin_port, ipv4_prefix,
137  ipv4_suffix);
138  }
139  return 0;
140 }
141 
142 const sockaddr *zmq::tcp_address_t::addr () const
143 {
144  return _address.as_sockaddr ();
145 }
146 
147 socklen_t zmq::tcp_address_t::addrlen () const
148 {
149  return _address.sockaddr_len ();
150 }
151 
152 const sockaddr *zmq::tcp_address_t::src_addr () const
153 {
154  return _source_address.as_sockaddr ();
155 }
156 
158 {
159  return _source_address.sockaddr_len ();
160 }
161 
163 {
164  return _has_src_addr;
165 }
166 
167 #if defined ZMQ_HAVE_WINDOWS
168 unsigned short zmq::tcp_address_t::family () const
169 #else
171 #endif
172 {
173  return _address.family ();
174 }
175 
177 {
178  memset (&_network_address, 0, sizeof (_network_address));
179 }
180 
181 int zmq::tcp_address_mask_t::resolve (const char *name_, bool ipv6_)
182 {
183  // Find '/' at the end that separates address from the cidr mask number.
184  // Allow empty mask clause and treat it like '/32' for ipv4 or '/128' for ipv6.
185  std::string addr_str, mask_str;
186  const char *delimiter = strrchr (name_, '/');
187  if (delimiter != NULL) {
188  addr_str.assign (name_, delimiter - name_);
189  mask_str.assign (delimiter + 1);
190  if (mask_str.empty ()) {
191  errno = EINVAL;
192  return -1;
193  }
194  } else
195  addr_str.assign (name_);
196 
197  // Parse address part using standard routines.
198  ip_resolver_options_t resolver_opts;
199 
200  resolver_opts.bindable (false)
201  .allow_dns (false)
202  .allow_nic_name (false)
203  .ipv6 (ipv6_)
204  .expect_port (false);
205 
206  ip_resolver_t resolver (resolver_opts);
207 
208  const int rc = resolver.resolve (&_network_address, addr_str.c_str ());
209  if (rc != 0)
210  return rc;
211 
212  // Parse the cidr mask number.
213  const int full_mask_ipv4 =
214  sizeof (_network_address.ipv4.sin_addr) * CHAR_BIT;
215  const int full_mask_ipv6 =
216  sizeof (_network_address.ipv6.sin6_addr) * CHAR_BIT;
217  if (mask_str.empty ()) {
218  _address_mask = _network_address.family () == AF_INET6 ? full_mask_ipv6
219  : full_mask_ipv4;
220  } else if (mask_str == "0")
221  _address_mask = 0;
222  else {
223  const long mask = strtol (mask_str.c_str (), NULL, 10);
224  if ((mask < 1)
225  || (_network_address.family () == AF_INET6 && mask > full_mask_ipv6)
226  || (_network_address.family () != AF_INET6
227  && mask > full_mask_ipv4)) {
228  errno = EINVAL;
229  return -1;
230  }
231  _address_mask = static_cast<int> (mask);
232  }
233 
234  return 0;
235 }
236 
237 bool zmq::tcp_address_mask_t::match_address (const struct sockaddr *ss_,
238  const socklen_t ss_len_) const
239 {
240  zmq_assert (_address_mask != -1 && ss_ != NULL
241  && ss_len_
242  >= static_cast<socklen_t> (sizeof (struct sockaddr)));
243 
244  if (ss_->sa_family != _network_address.generic.sa_family)
245  return false;
246 
247  if (_address_mask > 0) {
248  int mask;
249  const uint8_t *our_bytes, *their_bytes;
250  if (ss_->sa_family == AF_INET6) {
251  zmq_assert (ss_len_ == sizeof (struct sockaddr_in6));
252  their_bytes = reinterpret_cast<const uint8_t *> (
253  &((reinterpret_cast<const struct sockaddr_in6 *> (ss_))
254  ->sin6_addr));
255  our_bytes = reinterpret_cast<const uint8_t *> (
256  &_network_address.ipv6.sin6_addr);
257  mask = sizeof (struct in6_addr) * 8;
258  } else {
259  zmq_assert (ss_len_ == sizeof (struct sockaddr_in));
260  their_bytes = reinterpret_cast<const uint8_t *> (&(
261  (reinterpret_cast<const struct sockaddr_in *> (ss_))->sin_addr));
262  our_bytes = reinterpret_cast<const uint8_t *> (
263  &_network_address.ipv4.sin_addr);
264  mask = sizeof (struct in_addr) * 8;
265  }
266  if (_address_mask < mask)
267  mask = _address_mask;
268 
269  const size_t full_bytes = mask / 8;
270  if (memcmp (our_bytes, their_bytes, full_bytes) != 0)
271  return false;
272 
273  const uint8_t last_byte_bits = 0xffU << (8 - mask % 8);
274  if (last_byte_bits) {
275  if ((their_bytes[full_bytes] & last_byte_bits)
276  != (our_bytes[full_bytes] & last_byte_bits))
277  return false;
278  }
279  }
280 
281  return true;
282 }
zmq::ip_addr_t::ipv6
sockaddr_in6 ipv6
Definition: ip_resolver.hpp:20
zmq::tcp_address_t::to_string
int to_string(std::string &addr_) const
Definition: tcp_address.cpp:111
ip.hpp
zmq::tcp_address_t::addr
const sockaddr * addr() const
Definition: tcp_address.cpp:142
zmq::tcp_address_t::src_addrlen
socklen_t src_addrlen() const
Definition: tcp_address.cpp:157
zmq::ip_resolver_options_t::ipv6
ip_resolver_options_t & ipv6(bool ipv6_)
Definition: ip_resolver.cpp:121
benchmarks.python.py_benchmark.const
const
Definition: py_benchmark.py:14
NULL
NULL
Definition: test_security_zap.cpp:405
EINVAL
#define EINVAL
Definition: errno.hpp:25
precompiled.hpp
zmq_assert
#define zmq_assert(x)
Definition: err.hpp:102
zmq::tcp_address_t::_source_address
ip_addr_t _source_address
Definition: tcp_address.hpp:44
string
GLsizei const GLchar *const * string
Definition: glcorearb.h:3083
errno
int errno
zmq::ip_resolver_options_t::bindable
ip_resolver_options_t & bindable(bool bindable_)
Definition: ip_resolver.cpp:106
zmq::tcp_address_t::addrlen
socklen_t addrlen() const
Definition: tcp_address.cpp:147
snprintf
int snprintf(char *str, size_t size, const char *format,...)
Definition: port.cc:64
NI_MAXHOST
#define NI_MAXHOST
Definition: vxworks/platform.hpp:305
zmq::ip_addr_t::ipv4
sockaddr_in ipv4
Definition: ip_resolver.hpp:19
zmq::tcp_address_mask_t::match_address
bool match_address(const struct sockaddr *ss_, socklen_t ss_len_) const
Definition: tcp_address.cpp:237
macros.hpp
mask
GLint GLuint mask
Definition: glcorearb.h:2789
stdint.hpp
zmq::tcp_address_t::tcp_address_t
tcp_address_t()
Definition: tcp_address.cpp:25
zmq::tcp_address_t::family
sa_family_t family() const
Definition: tcp_address.cpp:170
zmq::tcp_address_t::resolve
int resolve(const char *name_, bool local_, bool ipv6_)
Definition: tcp_address.cpp:46
zmq::tcp_address_mask_t::_network_address
ip_addr_t _network_address
Definition: tcp_address.hpp:61
tcp_address.hpp
zmq::ip_resolver_options_t::allow_dns
ip_resolver_options_t & allow_dns(bool allow_)
Definition: ip_resolver.cpp:138
make_address_string
static std::string make_address_string(const char *hbuf_, uint16_t port_, const char(&ipv6_prefix_)[N1], const char(&ipv6_suffix_)[N2])
Definition: tcp_address.cpp:89
name_
string name_
Definition: googletest.cc:182
zmq::ip_resolver_t::resolve
int resolve(ip_addr_t *ip_addr_, const char *name_)
Definition: ip_resolver.cpp:187
buf
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glcorearb.h:4175
zmq::ip_resolver_options_t::expect_port
ip_resolver_options_t & expect_port(bool expect_)
Definition: ip_resolver.cpp:131
zmq::ip_resolver_t
Definition: ip_resolver.hpp:62
zmq::ip_resolver_options_t::allow_nic_name
ip_resolver_options_t & allow_nic_name(bool allow_)
Definition: ip_resolver.cpp:114
zmq::tcp_address_t::src_addr
const sockaddr * src_addr() const
Definition: tcp_address.cpp:152
zmq::tcp_address_t::_address
ip_addr_t _address
Definition: tcp_address.hpp:43
zmq::ip_resolver_options_t
Definition: ip_resolver.hpp:34
zmq::tcp_address_mask_t::tcp_address_mask_t
tcp_address_mask_t()
Definition: tcp_address.cpp:176
err.hpp
zmq::tcp_address_t::has_src_addr
bool has_src_addr() const
Definition: tcp_address.cpp:162
zmq::tcp_address_mask_t::resolve
int resolve(const char *name_, bool ipv6_)
Definition: tcp_address.cpp:181
false
#define false
Definition: cJSON.c:70


libaditof
Author(s):
autogenerated on Wed May 21 2025 02:06:59