1 /*
2 Copyright (c) 2007, Adobe Systems, Incorporated
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15
16 * Neither the name of Adobe Systems, Network Resonance nor the names of its
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <csi_platform.h>
34 #include <stdio.h>
35 #include <memory.h>
36 #include <sys/types.h>
37 #include <errno.h>
38 #ifdef WIN32
39 #include <winsock2.h>
40 #else
41 #include <unistd.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #endif
46 #include <assert.h>
47 #include "nr_api.h"
48 #include "util.h"
49 #include "transport_addr.h"
50
nr_transport_addr_fmt_addr_string(nr_transport_addr * addr)51 int nr_transport_addr_fmt_addr_string(nr_transport_addr *addr)
52 {
53 int _status;
54 /* Max length for normalized IPv6 address string representation is 39 */
55 char buffer[40];
56 const char *protocol;
57
58 switch(addr->protocol){
59 case IPPROTO_TCP:
60 if (addr->tls) {
61 protocol = "TLS";
62 } else {
63 protocol = "TCP";
64 }
65 break;
66 case IPPROTO_UDP:
67 protocol = "UDP";
68 break;
69 default:
70 ABORT(R_INTERNAL);
71 }
72
73 switch(addr->ip_version){
74 case NR_IPV4:
75 if (!inet_ntop(AF_INET, &addr->u.addr4.sin_addr,buffer,sizeof(buffer)))
76 strcpy(buffer, "[error]");
77 snprintf(addr->as_string,sizeof(addr->as_string),"IP4:%s:%d/%s",buffer,(int)ntohs(addr->u.addr4.sin_port),protocol);
78 break;
79 case NR_IPV6:
80 if (!inet_ntop(AF_INET6, &addr->u.addr6.sin6_addr,buffer,sizeof(buffer)))
81 strcpy(buffer, "[error]");
82 snprintf(addr->as_string,sizeof(addr->as_string),"IP6:[%s]:%d/%s",buffer,(int)ntohs(addr->u.addr6.sin6_port),protocol);
83 break;
84 default:
85 ABORT(R_INTERNAL);
86 }
87
88 _status=0;
89 abort:
90 return(_status);
91 }
92
nr_transport_addr_fmt_ifname_addr_string(const nr_transport_addr * addr,char * buf,int len)93 int nr_transport_addr_fmt_ifname_addr_string(const nr_transport_addr *addr, char *buf, int len)
94 {
95 int _status;
96 /* leave room for a fully-expanded IPV4-mapped IPV6 address */
97 char buffer[46];
98
99 switch(addr->ip_version){
100 case NR_IPV4:
101 if (!inet_ntop(AF_INET, &addr->u.addr4.sin_addr,buffer,sizeof(buffer))) {
102 strncpy(buffer, "[error]", sizeof(buffer));
103 }
104 break;
105 case NR_IPV6:
106 if (!inet_ntop(AF_INET6, &addr->u.addr6.sin6_addr,buffer,sizeof(buffer))) {
107 strncpy(buffer, "[error]", sizeof(buffer));
108 }
109 break;
110 default:
111 ABORT(R_INTERNAL);
112 }
113 buffer[sizeof(buffer) - 1] = '\0';
114
115 snprintf(buf,len,"%s:%s",addr->ifname,buffer);
116 buf[len - 1] = '\0';
117
118 _status=0;
119 abort:
120 return(_status);
121 }
122
nr_sockaddr_to_transport_addr(struct sockaddr * saddr,int protocol,int keep,nr_transport_addr * addr)123 int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int protocol, int keep, nr_transport_addr *addr)
124 {
125 int r,_status;
126
127 if(!keep) memset(addr,0,sizeof(nr_transport_addr));
128
129 switch(protocol){
130 case IPPROTO_TCP:
131 case IPPROTO_UDP:
132 break;
133 default:
134 ABORT(R_BAD_ARGS);
135 }
136
137 addr->protocol=protocol;
138
139 if(saddr->sa_family==AF_INET){
140 addr->ip_version=NR_IPV4;
141
142 memcpy(&addr->u.addr4,saddr,sizeof(struct sockaddr_in));
143 }
144 else if(saddr->sa_family==AF_INET6){
145 addr->ip_version=NR_IPV6;
146
147 memcpy(&addr->u.addr6, saddr, sizeof(struct sockaddr_in6));
148 }
149 else
150 ABORT(R_BAD_ARGS);
151
152 if(r=nr_transport_addr_fmt_addr_string(addr))
153 ABORT(r);
154
155 _status=0;
156 abort:
157 return(_status);
158 }
159
160
nr_transport_addr_copy(nr_transport_addr * to,const nr_transport_addr * from)161 int nr_transport_addr_copy(nr_transport_addr *to, const nr_transport_addr *from)
162 {
163 memcpy(to,from,sizeof(nr_transport_addr));
164 return 0;
165 }
166
nr_transport_addr_copy_keep_ifname(nr_transport_addr * to,const nr_transport_addr * from)167 int nr_transport_addr_copy_keep_ifname(nr_transport_addr *to, const nr_transport_addr *from)
168 {
169 int r,_status;
170 char save_ifname[MAXIFNAME];
171
172 strncpy(save_ifname, to->ifname, MAXIFNAME);
173 save_ifname[MAXIFNAME-1]=0; /* Ensure null termination */
174
175 if (r=nr_transport_addr_copy(to, from))
176 ABORT(r);
177
178 strncpy(to->ifname, save_ifname, MAXIFNAME);
179
180 if (r=nr_transport_addr_fmt_addr_string(to))
181 ABORT(r);
182
183 _status=0;
184 abort:
185 return _status;
186 }
187
nr_transport_addr_copy_addrport(nr_transport_addr * to,const nr_transport_addr * from)188 int nr_transport_addr_copy_addrport(nr_transport_addr *to, const nr_transport_addr *from)
189 {
190 int r,_status;
191
192 switch (from->ip_version) {
193 case NR_IPV4:
194 memcpy(&to->u.addr4, &from->u.addr4, sizeof(to->u.addr4));
195 break;
196 case NR_IPV6:
197 memcpy(&to->u.addr6, &from->u.addr6, sizeof(to->u.addr6));
198 break;
199 default:
200 ABORT(R_BAD_ARGS);
201 }
202
203 to->ip_version = from->ip_version;
204
205 if (r=nr_transport_addr_fmt_addr_string(to)) {
206 ABORT(r);
207 }
208
209 _status=0;
210 abort:
211 return _status;
212 }
213
214 /* Convenience fxn. Is this the right API?*/
nr_ip4_port_to_transport_addr(UINT4 ip4,UINT2 port,int protocol,nr_transport_addr * addr)215 int nr_ip4_port_to_transport_addr(UINT4 ip4, UINT2 port, int protocol, nr_transport_addr *addr)
216 {
217 int r,_status;
218
219 memset(addr, 0, sizeof(nr_transport_addr));
220
221 addr->ip_version=NR_IPV4;
222 addr->protocol=protocol;
223 #ifdef HAVE_SIN_LEN
224 addr->u.addr4.sin_len=sizeof(struct sockaddr_in);
225 #endif
226 addr->u.addr4.sin_family=PF_INET;
227 addr->u.addr4.sin_port=htons(port);
228 addr->u.addr4.sin_addr.s_addr=htonl(ip4);
229
230 if(r=nr_transport_addr_fmt_addr_string(addr))
231 ABORT(r);
232
233 _status=0;
234 abort:
235 return(_status);
236 }
237
nr_str_port_to_transport_addr(const char * ip,UINT2 port,int protocol,nr_transport_addr * addr_out)238 int nr_str_port_to_transport_addr(const char *ip, UINT2 port, int protocol, nr_transport_addr *addr_out)
239 {
240 int r,_status;
241 struct in_addr addr;
242 struct in6_addr addr6;
243
244 if (inet_pton(AF_INET, ip, &addr) == 1) {
245 if(r=nr_ip4_port_to_transport_addr(ntohl(addr.s_addr),port,protocol,addr_out))
246 ABORT(r);
247 } else if (inet_pton(AF_INET6, ip, &addr6) == 1) {
248 if(r=nr_ip6_port_to_transport_addr(&addr6,port,protocol,addr_out))
249 ABORT(r);
250 } else {
251 ABORT(R_BAD_DATA);
252 }
253
254 _status=0;
255 abort:
256 return(_status);
257 }
258
nr_ip6_port_to_transport_addr(struct in6_addr * addr6,UINT2 port,int protocol,nr_transport_addr * addr)259 int nr_ip6_port_to_transport_addr(struct in6_addr* addr6, UINT2 port, int protocol, nr_transport_addr *addr)
260 {
261 int r,_status;
262
263 memset(addr, 0, sizeof(nr_transport_addr));
264
265 addr->ip_version=NR_IPV6;
266 addr->protocol=protocol;
267 addr->u.addr6.sin6_family=PF_INET6;
268 addr->u.addr6.sin6_port=htons(port);
269 memcpy(addr->u.addr6.sin6_addr.s6_addr, addr6->s6_addr, sizeof(addr6->s6_addr));
270
271 if(r=nr_transport_addr_fmt_addr_string(addr))
272 ABORT(r);
273
274 _status=0;
275 abort:
276 return(_status);
277 }
278
nr_transport_addr_get_addrstring(const nr_transport_addr * addr,char * str,int maxlen)279 int nr_transport_addr_get_addrstring(const nr_transport_addr *addr, char *str, int maxlen)
280 {
281 int _status;
282
283 if (addr->fqdn[0]) {
284 strncpy(str, addr->fqdn, maxlen);
285 } else {
286 const char* res;
287 switch (addr->ip_version) {
288 case NR_IPV4:
289 res = inet_ntop(AF_INET, &addr->u.addr4.sin_addr, str, maxlen);
290 break;
291 case NR_IPV6:
292 res = inet_ntop(AF_INET6, &addr->u.addr6.sin6_addr, str, maxlen);
293 break;
294 default:
295 ABORT(R_INTERNAL);
296 }
297
298 if (!res) {
299 if (errno == ENOSPC) {
300 ABORT(R_BAD_ARGS);
301 }
302 ABORT(R_INTERNAL);
303 }
304 }
305
306 _status=0;
307 abort:
308 return(_status);
309 }
310
nr_transport_addr_get_port(const nr_transport_addr * addr,int * port)311 int nr_transport_addr_get_port(const nr_transport_addr *addr, int *port)
312 {
313 int _status;
314
315 switch(addr->ip_version){
316 case NR_IPV4:
317 *port=ntohs(addr->u.addr4.sin_port);
318 break;
319 case NR_IPV6:
320 *port=ntohs(addr->u.addr6.sin6_port);
321 break;
322 default:
323 ABORT(R_INTERNAL);
324 }
325
326 _status=0;
327 abort:
328 return(_status);
329 }
330
nr_transport_addr_set_port(nr_transport_addr * addr,int port)331 int nr_transport_addr_set_port(nr_transport_addr *addr, int port)
332 {
333 int _status;
334
335 switch(addr->ip_version){
336 case NR_IPV4:
337 addr->u.addr4.sin_port=htons(port);
338 break;
339 case NR_IPV6:
340 addr->u.addr6.sin6_port=htons(port);
341 break;
342 default:
343 ABORT(R_INTERNAL);
344 }
345
346 _status=0;
347 abort:
348 return(_status);
349 }
350
351 /* memcmp() may not work if, for instance, the string or interface
352 haven't been made. Hmmm.. */
nr_transport_addr_cmp(const nr_transport_addr * addr1,const nr_transport_addr * addr2,int mode)353 int nr_transport_addr_cmp(const nr_transport_addr *addr1,const nr_transport_addr *addr2,int mode)
354 {
355 assert(mode);
356
357 if(addr1->ip_version != addr2->ip_version)
358 return(1);
359
360 if(mode < NR_TRANSPORT_ADDR_CMP_MODE_PROTOCOL)
361 return(0);
362
363 if(addr1->protocol != addr2->protocol)
364 return(1);
365
366 if(mode < NR_TRANSPORT_ADDR_CMP_MODE_ADDR)
367 return(0);
368
369 switch(addr1->ip_version){
370 case NR_IPV4:
371 if(addr1->u.addr4.sin_addr.s_addr != addr2->u.addr4.sin_addr.s_addr)
372 return(1);
373 if(mode < NR_TRANSPORT_ADDR_CMP_MODE_ALL)
374 return(0);
375 if(addr1->u.addr4.sin_port != addr2->u.addr4.sin_port)
376 return(1);
377 break;
378 case NR_IPV6:
379 if(memcmp(addr1->u.addr6.sin6_addr.s6_addr,addr2->u.addr6.sin6_addr.s6_addr,sizeof(struct in6_addr)))
380 return(1);
381 if(mode < NR_TRANSPORT_ADDR_CMP_MODE_ALL)
382 return(0);
383 if(addr1->u.addr6.sin6_port != addr2->u.addr6.sin6_port)
384 return(1);
385 break;
386 default:
387 abort();
388 }
389
390 return(0);
391 }
392
nr_transport_addr_is_loopback(const nr_transport_addr * addr)393 int nr_transport_addr_is_loopback(const nr_transport_addr *addr)
394 {
395 switch(addr->ip_version){
396 case NR_IPV4:
397 switch(addr->u.addr4.sin_family){
398 case AF_INET:
399 if (((ntohl(addr->u.addr4.sin_addr.s_addr)>>24)&0xff)==0x7f)
400 return 1;
401 break;
402 default:
403 NR_UNIMPLEMENTED;
404 break;
405 }
406 break;
407
408 case NR_IPV6:
409 if(!memcmp(addr->u.addr6.sin6_addr.s6_addr,in6addr_loopback.s6_addr,sizeof(struct in6_addr)))
410 return(1);
411 break;
412 default:
413 NR_UNIMPLEMENTED;
414 }
415
416 return(0);
417 }
418
nr_transport_addr_is_link_local(const nr_transport_addr * addr)419 int nr_transport_addr_is_link_local(const nr_transport_addr *addr)
420 {
421 switch(addr->ip_version){
422 case NR_IPV4:
423 /* RFC3927: 169.254/16 */
424 if ((ntohl(addr->u.addr4.sin_addr.s_addr) & 0xFFFF0000) == 0xA9FE0000)
425 return(1);
426 break;
427 case NR_IPV6:
428 {
429 UINT4* addrTop = (UINT4*)(addr->u.addr6.sin6_addr.s6_addr);
430 if ((*addrTop & htonl(0xFFC00000)) == htonl(0xFE800000))
431 return(2);
432 }
433 break;
434 default:
435 NR_UNIMPLEMENTED;
436 }
437
438 return(0);
439 }
440
nr_transport_addr_is_mac_based(const nr_transport_addr * addr)441 int nr_transport_addr_is_mac_based(const nr_transport_addr *addr)
442 {
443 switch(addr->ip_version){
444 case NR_IPV4:
445 // IPv4 has no MAC based self assigned IP addresses
446 return(0);
447 case NR_IPV6:
448 {
449 // RFC 2373, Appendix A: lower 64bit 0x020000FFFE000000
450 // indicates a MAC based IPv6 address
451 UINT4* macCom = (UINT4*)(addr->u.addr6.sin6_addr.s6_addr + 8);
452 UINT4* macExt = (UINT4*)(addr->u.addr6.sin6_addr.s6_addr + 12);
453 if ((*macCom & htonl(0x020000FF)) == htonl(0x020000FF) &&
454 (*macExt & htonl(0xFF000000)) == htonl(0xFE000000)) {
455 return(1);
456 }
457 }
458 break;
459 default:
460 NR_UNIMPLEMENTED;
461 }
462 return(0);
463 }
464
nr_transport_addr_is_teredo(const nr_transport_addr * addr)465 int nr_transport_addr_is_teredo(const nr_transport_addr *addr)
466 {
467 switch(addr->ip_version){
468 case NR_IPV4:
469 return(0);
470 case NR_IPV6:
471 {
472 UINT4* addrTop = (UINT4*)(addr->u.addr6.sin6_addr.s6_addr);
473 if ((*addrTop & htonl(0xFFFFFFFF)) == htonl(0x20010000))
474 return(1);
475 }
476 break;
477 default:
478 NR_UNIMPLEMENTED;
479 }
480
481 return(0);
482 }
483
nr_transport_addr_check_compatibility(const nr_transport_addr * addr1,const nr_transport_addr * addr2)484 int nr_transport_addr_check_compatibility(const nr_transport_addr *addr1, const nr_transport_addr *addr2)
485 {
486 // first make sure we're comparing the same ip versions and protocols
487 if ((addr1->ip_version != addr2->ip_version) ||
488 (addr1->protocol != addr2->protocol)) {
489 return(1);
490 }
491
492 if (!addr1->fqdn[0] && !addr2->fqdn[0]) {
493 // now make sure the link local status matches
494 if (nr_transport_addr_is_link_local(addr1) !=
495 nr_transport_addr_is_link_local(addr2)) {
496 return(1);
497 }
498 }
499 return(0);
500 }
501
nr_transport_addr_is_wildcard(const nr_transport_addr * addr)502 int nr_transport_addr_is_wildcard(const nr_transport_addr *addr)
503 {
504 switch(addr->ip_version){
505 case NR_IPV4:
506 if(addr->u.addr4.sin_addr.s_addr==INADDR_ANY)
507 return(1);
508 if(addr->u.addr4.sin_port==0)
509 return(1);
510 break;
511 case NR_IPV6:
512 if(!memcmp(addr->u.addr6.sin6_addr.s6_addr,in6addr_any.s6_addr,sizeof(struct in6_addr)))
513 return(1);
514 if(addr->u.addr6.sin6_port==0)
515 return(1);
516 break;
517 default:
518 NR_UNIMPLEMENTED;
519 }
520
521 return(0);
522 }
523
524 nr_transport_addr_mask nr_private_ipv4_addrs[] = {
525 /* RFC1918: 10/8 */
526 {0x0A000000, 0xFF000000},
527 /* RFC1918: 172.16/12 */
528 {0xAC100000, 0xFFF00000},
529 /* RFC1918: 192.168/16 */
530 {0xC0A80000, 0xFFFF0000},
531 /* RFC6598: 100.64/10 */
532 {0x64400000, 0xFFC00000}
533 };
534
nr_transport_addr_get_private_addr_range(const nr_transport_addr * addr)535 int nr_transport_addr_get_private_addr_range(const nr_transport_addr *addr)
536 {
537 switch(addr->ip_version){
538 case NR_IPV4:
539 {
540 UINT4 ip = ntohl(addr->u.addr4.sin_addr.s_addr);
541 for (size_t i=0; i<(sizeof(nr_private_ipv4_addrs)/sizeof(nr_transport_addr_mask)); i++) {
542 if ((ip & nr_private_ipv4_addrs[i].mask) == nr_private_ipv4_addrs[i].addr)
543 return i + 1;
544 }
545 }
546 break;
547 case NR_IPV6:
548 return(0);
549 default:
550 NR_UNIMPLEMENTED;
551 }
552
553 return(0);
554 }
555
nr_transport_addr_is_reliable_transport(const nr_transport_addr * addr)556 int nr_transport_addr_is_reliable_transport(const nr_transport_addr *addr)
557 {
558 return addr->protocol == IPPROTO_TCP;
559 }
560