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 
34 
35 static char *RCSSTRING __UNUSED__="$Id: transport_addr.c,v 1.2 2008/04/28 17:59:03 ekr Exp $";
36 
37 
38 #include <csi_platform.h>
39 #include <stdio.h>
40 #include <memory.h>
41 #include <sys/types.h>
42 #include <errno.h>
43 #ifdef WIN32
44 #include <winsock2.h>
45 #else
46 #include <unistd.h>
47 #include <sys/socket.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
50 #endif
51 #include <assert.h>
52 #include "nr_api.h"
53 #include "util.h"
54 #include "transport_addr.h"
55 
nr_transport_addr_fmt_addr_string(nr_transport_addr * addr)56 int nr_transport_addr_fmt_addr_string(nr_transport_addr *addr)
57   {
58     int _status;
59     /* Max length for normalized IPv6 address string representation is 39 */
60     char buffer[40];
61     const char *protocol;
62 
63     switch(addr->protocol){
64       case IPPROTO_TCP:
65         protocol = "TCP";
66         break;
67       case IPPROTO_UDP:
68         protocol = "UDP";
69         break;
70       default:
71         ABORT(R_INTERNAL);
72     }
73 
74     switch(addr->ip_version){
75       case NR_IPV4:
76         if (!inet_ntop(AF_INET, &addr->u.addr4.sin_addr,buffer,sizeof(buffer)))
77           strcpy(buffer, "[error]");
78         snprintf(addr->as_string,sizeof(addr->as_string),"IP4:%s:%d/%s",buffer,(int)ntohs(addr->u.addr4.sin_port),protocol);
79         break;
80       case NR_IPV6:
81         if (!inet_ntop(AF_INET6, &addr->u.addr6.sin6_addr,buffer,sizeof(buffer)))
82           strcpy(buffer, "[error]");
83         snprintf(addr->as_string,sizeof(addr->as_string),"IP6:[%s]:%d/%s",buffer,(int)ntohs(addr->u.addr6.sin6_port),protocol);
84         break;
85       default:
86         ABORT(R_INTERNAL);
87     }
88 
89     _status=0;
90   abort:
91     return(_status);
92   }
93 
nr_transport_addr_fmt_ifname_addr_string(const nr_transport_addr * addr,char * buf,int len)94 int nr_transport_addr_fmt_ifname_addr_string(const nr_transport_addr *addr, char *buf, int len)
95   {
96     int _status;
97     char buffer[40];
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]", len);
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]", len);
108         }
109         break;
110       default:
111         ABORT(R_INTERNAL);
112     }
113     snprintf(buf,len,"%s:%s",addr->ifname,buffer);
114 
115     _status=0;
116   abort:
117     return(_status);
118   }
119 
nr_sockaddr_to_transport_addr(struct sockaddr * saddr,int protocol,int keep,nr_transport_addr * addr)120 int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int protocol, int keep, nr_transport_addr *addr)
121   {
122     int r,_status;
123 
124     if(!keep) memset(addr,0,sizeof(nr_transport_addr));
125 
126     switch(protocol){
127       case IPPROTO_TCP:
128       case IPPROTO_UDP:
129         break;
130       default:
131         ABORT(R_BAD_ARGS);
132     }
133 
134     addr->protocol=protocol;
135 
136     if(saddr->sa_family==AF_INET){
137       addr->ip_version=NR_IPV4;
138 
139       memcpy(&addr->u.addr4,saddr,sizeof(struct sockaddr_in));
140       addr->addr=(struct sockaddr *)&addr->u.addr4;
141       addr->addr_len=sizeof(struct sockaddr_in);
142     }
143     else if(saddr->sa_family==AF_INET6){
144       addr->ip_version=NR_IPV6;
145 
146       memcpy(&addr->u.addr6, saddr, sizeof(struct sockaddr_in6));
147       addr->addr=(struct sockaddr *)&addr->u.addr6;
148       addr->addr_len=sizeof(struct sockaddr_in6);
149     }
150     else
151       ABORT(R_BAD_ARGS);
152 
153     if(r=nr_transport_addr_fmt_addr_string(addr))
154       ABORT(r);
155 
156     _status=0;
157   abort:
158     return(_status);
159   }
160 
161 
nr_transport_addr_copy(nr_transport_addr * to,nr_transport_addr * from)162 int nr_transport_addr_copy(nr_transport_addr *to, nr_transport_addr *from)
163   {
164     memcpy(to,from,sizeof(nr_transport_addr));
165     to->addr=(struct sockaddr *)((char *)to + ((char *)from->addr - (char *)from));
166 
167     return(0);
168   }
169 
nr_transport_addr_copy_keep_ifname(nr_transport_addr * to,nr_transport_addr * from)170 int nr_transport_addr_copy_keep_ifname(nr_transport_addr *to, nr_transport_addr *from)
171   {
172     int r,_status;
173     char save_ifname[MAXIFNAME];
174 
175     strncpy(save_ifname, to->ifname, MAXIFNAME);
176     save_ifname[MAXIFNAME-1]=0;  /* Ensure null termination */
177 
178     if (r=nr_transport_addr_copy(to, from))
179       ABORT(r);
180 
181     strncpy(to->ifname, save_ifname, MAXIFNAME);
182 
183     if (r=nr_transport_addr_fmt_addr_string(to))
184       ABORT(r);
185 
186     _status=0;
187  abort:
188     return _status;
189   }
190 
191 /* Convenience fxn. Is this the right API?*/
nr_ip4_port_to_transport_addr(UINT4 ip4,UINT2 port,int protocol,nr_transport_addr * addr)192 int nr_ip4_port_to_transport_addr(UINT4 ip4, UINT2 port, int protocol, nr_transport_addr *addr)
193   {
194     int r,_status;
195 
196     memset(addr, 0, sizeof(nr_transport_addr));
197 
198     addr->ip_version=NR_IPV4;
199     addr->protocol=protocol;
200 #ifdef HAVE_SIN_LEN
201     addr->u.addr4.sin_len=sizeof(struct sockaddr_in);
202 #endif
203     addr->u.addr4.sin_family=PF_INET;
204     addr->u.addr4.sin_port=htons(port);
205     addr->u.addr4.sin_addr.s_addr=htonl(ip4);
206     addr->addr=(struct sockaddr *)&addr->u.addr4;
207     addr->addr_len=sizeof(struct sockaddr_in);
208 
209     if(r=nr_transport_addr_fmt_addr_string(addr))
210       ABORT(r);
211 
212     _status=0;
213   abort:
214     return(_status);
215   }
216 
nr_str_port_to_transport_addr(const char * ip,UINT2 port,int protocol,nr_transport_addr * addr_out)217 int nr_str_port_to_transport_addr(const char *ip, UINT2 port, int protocol, nr_transport_addr *addr_out)
218   {
219     int r,_status;
220     struct in_addr addr;
221     struct in6_addr addr6;
222 
223     if (inet_pton(AF_INET, ip, &addr) == 1) {
224       if(r=nr_ip4_port_to_transport_addr(ntohl(addr.s_addr),port,protocol,addr_out))
225         ABORT(r);
226     } else if (inet_pton(AF_INET6, ip, &addr6) == 1) {
227       if(r=nr_ip6_port_to_transport_addr(&addr6,port,protocol,addr_out))
228         ABORT(r);
229     } else {
230       ABORT(R_BAD_DATA);
231     }
232 
233     _status=0;
234   abort:
235     return(_status);
236   }
237 
nr_ip6_port_to_transport_addr(struct in6_addr * addr6,UINT2 port,int protocol,nr_transport_addr * addr)238 int nr_ip6_port_to_transport_addr(struct in6_addr* addr6, UINT2 port, int protocol, nr_transport_addr *addr)
239   {
240     int r,_status;
241 
242     memset(addr, 0, sizeof(nr_transport_addr));
243 
244     addr->ip_version=NR_IPV6;
245     addr->protocol=protocol;
246     addr->u.addr6.sin6_family=PF_INET6;
247     addr->u.addr6.sin6_port=htons(port);
248     memcpy(addr->u.addr6.sin6_addr.s6_addr, addr6->s6_addr, sizeof(addr6->s6_addr));
249     addr->addr=(struct sockaddr *)&addr->u.addr6;
250     addr->addr_len=sizeof(struct sockaddr_in6);
251 
252     if(r=nr_transport_addr_fmt_addr_string(addr))
253       ABORT(r);
254 
255     _status=0;
256   abort:
257     return(_status);
258   }
259 
nr_transport_addr_get_addrstring(const nr_transport_addr * addr,char * str,int maxlen)260 int nr_transport_addr_get_addrstring(const nr_transport_addr *addr, char *str, int maxlen)
261   {
262     int _status;
263     const char *res;
264 
265     switch(addr->ip_version){
266       case NR_IPV4:
267         res = inet_ntop(AF_INET, &addr->u.addr4.sin_addr,str,maxlen);
268         break;
269       case NR_IPV6:
270         res = inet_ntop(AF_INET6, &addr->u.addr6.sin6_addr,str,maxlen);
271         break;
272       default:
273         ABORT(R_INTERNAL);
274     }
275 
276     if(!res){
277       if (errno == ENOSPC){
278         ABORT(R_BAD_ARGS);
279       }
280       ABORT(R_INTERNAL);
281     }
282 
283     _status=0;
284   abort:
285     return(_status);
286   }
287 
nr_transport_addr_get_port(nr_transport_addr * addr,int * port)288 int nr_transport_addr_get_port(nr_transport_addr *addr, int *port)
289   {
290     int _status;
291 
292     switch(addr->ip_version){
293       case NR_IPV4:
294         *port=ntohs(addr->u.addr4.sin_port);
295         break;
296       case NR_IPV6:
297         *port=ntohs(addr->u.addr6.sin6_port);
298         break;
299       default:
300         ABORT(R_INTERNAL);
301     }
302 
303     _status=0;
304   abort:
305     return(_status);
306   }
307 
nr_transport_addr_set_port(nr_transport_addr * addr,int port)308 int nr_transport_addr_set_port(nr_transport_addr *addr, int port)
309   {
310     int _status;
311 
312     switch(addr->ip_version){
313       case NR_IPV4:
314         addr->u.addr4.sin_port=htons(port);
315         break;
316       case NR_IPV6:
317         addr->u.addr6.sin6_port=htons(port);
318         break;
319       default:
320         ABORT(R_INTERNAL);
321     }
322 
323     _status=0;
324   abort:
325     return(_status);
326   }
327 
328 /* memcmp() may not work if, for instance, the string or interface
329    haven't been made. Hmmm.. */
nr_transport_addr_cmp(nr_transport_addr * addr1,nr_transport_addr * addr2,int mode)330 int nr_transport_addr_cmp(nr_transport_addr *addr1,nr_transport_addr *addr2,int mode)
331   {
332     assert(mode);
333 
334     if(addr1->ip_version != addr2->ip_version)
335       return(1);
336 
337     if(mode < NR_TRANSPORT_ADDR_CMP_MODE_PROTOCOL)
338       return(0);
339 
340     if(addr1->protocol != addr2->protocol)
341       return(1);
342 
343     if(mode < NR_TRANSPORT_ADDR_CMP_MODE_ADDR)
344       return(0);
345 
346     assert(addr1->addr_len == addr2->addr_len);
347     switch(addr1->ip_version){
348       case NR_IPV4:
349         if(addr1->u.addr4.sin_addr.s_addr != addr2->u.addr4.sin_addr.s_addr)
350           return(1);
351         if(mode < NR_TRANSPORT_ADDR_CMP_MODE_ALL)
352           return(0);
353         if(addr1->u.addr4.sin_port != addr2->u.addr4.sin_port)
354           return(1);
355         break;
356       case NR_IPV6:
357         if(memcmp(addr1->u.addr6.sin6_addr.s6_addr,addr2->u.addr6.sin6_addr.s6_addr,sizeof(struct in6_addr)))
358           return(1);
359         if(mode < NR_TRANSPORT_ADDR_CMP_MODE_ALL)
360           return(0);
361         if(addr1->u.addr6.sin6_port != addr2->u.addr6.sin6_port)
362           return(1);
363         break;
364       default:
365         abort();
366     }
367 
368     return(0);
369   }
370 
nr_transport_addr_is_loopback(nr_transport_addr * addr)371 int nr_transport_addr_is_loopback(nr_transport_addr *addr)
372   {
373     switch(addr->ip_version){
374       case NR_IPV4:
375         switch(addr->u.addr4.sin_family){
376           case AF_INET:
377             if (((ntohl(addr->u.addr4.sin_addr.s_addr)>>24)&0xff)==0x7f)
378               return 1;
379             break;
380           default:
381             UNIMPLEMENTED;
382             break;
383         }
384         break;
385 
386       case NR_IPV6:
387         if(!memcmp(addr->u.addr6.sin6_addr.s6_addr,in6addr_loopback.s6_addr,sizeof(struct in6_addr)))
388           return(1);
389         break;
390       default:
391         UNIMPLEMENTED;
392     }
393 
394     return(0);
395   }
396 
nr_transport_addr_is_link_local(nr_transport_addr * addr)397 int nr_transport_addr_is_link_local(nr_transport_addr *addr)
398   {
399     switch(addr->ip_version){
400       case NR_IPV4:
401         /* RFC3927: 169.254/16 */
402         if ((ntohl(addr->u.addr4.sin_addr.s_addr) & 0xFFFF0000) == 0xA9FE0000)
403           return(1);
404         break;
405       case NR_IPV6:
406         {
407           UINT4* addrTop = (UINT4*)(addr->u.addr6.sin6_addr.s6_addr);
408           if ((*addrTop & htonl(0xFFC00000)) == htonl(0xFE800000))
409             return(2);
410         }
411         break;
412       default:
413         UNIMPLEMENTED;
414     }
415 
416     return(0);
417   }
418 
nr_transport_addr_is_wildcard(nr_transport_addr * addr)419 int nr_transport_addr_is_wildcard(nr_transport_addr *addr)
420   {
421     switch(addr->ip_version){
422       case NR_IPV4:
423         if(addr->u.addr4.sin_addr.s_addr==INADDR_ANY)
424           return(1);
425         if(addr->u.addr4.sin_port==0)
426           return(1);
427         break;
428       case NR_IPV6:
429         if(!memcmp(addr->u.addr6.sin6_addr.s6_addr,in6addr_any.s6_addr,sizeof(struct in6_addr)))
430           return(1);
431         if(addr->u.addr6.sin6_port==0)
432           return(1);
433         break;
434       default:
435         UNIMPLEMENTED;
436     }
437 
438     return(0);
439   }
440 
441 nr_transport_addr_mask nr_private_ipv4_addrs[] = {
442   /* RFC1918: 10/8 */
443   {0x0A000000, 0xFF000000},
444   /* RFC1918: 172.16/12 */
445   {0xAC100000, 0xFFF00000},
446   /* RFC1918: 192.168/16 */
447   {0xC0A80000, 0xFFFF0000},
448   /* RFC6598: 100.64/10 */
449   {0x64400000, 0xFFC00000}
450 };
451 
nr_transport_addr_get_private_addr_range(nr_transport_addr * addr)452 int nr_transport_addr_get_private_addr_range(nr_transport_addr *addr)
453   {
454     switch(addr->ip_version){
455       case NR_IPV4:
456         {
457           UINT4 ip = ntohl(addr->u.addr4.sin_addr.s_addr);
458           for (int i=0; i<(sizeof(nr_private_ipv4_addrs)/sizeof(nr_transport_addr_mask)); i++) {
459             if ((ip & nr_private_ipv4_addrs[i].mask) == nr_private_ipv4_addrs[i].addr)
460               return i + 1;
461           }
462         }
463         break;
464       case NR_IPV6:
465         return(0);
466       default:
467         UNIMPLEMENTED;
468     }
469 
470     return(0);
471   }
472 
nr_transport_addr_is_reliable_transport(nr_transport_addr * addr)473 int nr_transport_addr_is_reliable_transport(nr_transport_addr *addr)
474   {
475     return addr->protocol == IPPROTO_TCP;
476   }
477