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