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