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