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