2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Various sorts of access control
23 * \author Mark Spencer <markster@digium.com>
28 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
39 #include <sys/socket.h>
42 #include <netinet/in_systm.h>
43 #include <netinet/ip.h>
44 #include <sys/ioctl.h>
46 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__Darwin__)
48 #include <net/route.h>
52 #include <sys/sockio.h>
54 #elif defined(HAVE_GETIFADDRS)
58 /* netinet/ip.h may not define the following (See RFCs 791 and 1349) */
59 #if !defined(IPTOS_LOWCOST)
60 #define IPTOS_LOWCOST 0x02
63 #if !defined(IPTOS_MINCOST)
64 #define IPTOS_MINCOST IPTOS_LOWCOST
67 #include "asterisk/acl.h"
68 #include "asterisk/logger.h"
69 #include "asterisk/channel.h"
70 #include "asterisk/options.h"
71 #include "asterisk/utils.h"
72 #include "asterisk/lock.h"
73 #include "asterisk/srv.h"
76 /* Host access rule */
77 struct in_addr netaddr
;
78 struct in_addr netmask
;
83 /* Default IP - if not otherwise set, don't breathe garbage */
84 static struct in_addr __ourip
= { .s_addr
= 0x00000000, };
87 char ifrn_name
[IFNAMSIZ
]; /* Interface name, e.g. "eth0", "ppp0", etc. */
88 struct sockaddr_in ifru_addr
;
91 #if (!defined(SOLARIS) && !defined(HAVE_GETIFADDRS))
92 static int get_local_address(struct in_addr
*ourip
)
97 static void score_address(const struct sockaddr_in
*sin
, struct in_addr
*best_addr
, int *best_score
)
102 address
= ast_inet_ntoa(sin
->sin_addr
);
104 /* RFC 1700 alias for the local network */
105 if (address
[0] == '0')
107 /* RFC 1700 localnet */
108 else if (strncmp(address
, "127", 3) == 0)
110 /* RFC 1918 non-public address space */
111 else if (strncmp(address
, "10.", 3) == 0)
113 /* RFC 1918 non-public address space */
114 else if (strncmp(address
, "172", 3) == 0) {
115 /* 172.16.0.0 - 172.19.255.255, but not 172.160.0.0 - 172.169.255.255 */
116 if (address
[4] == '1' && address
[5] >= '6' && address
[6] == '.')
118 /* 172.20.0.0 - 172.29.255.255, but not 172.200.0.0 - 172.255.255.255 nor 172.2.0.0 - 172.2.255.255 */
119 else if (address
[4] == '2' && address
[6] == '.')
121 /* 172.30.0.0 - 172.31.255.255 */
122 else if (address
[4] == '3' && address
[5] <= '1')
124 /* All other 172 addresses are public */
127 /* RFC 2544 Benchmark test range */
128 } else if (strncmp(address
, "198.1", 5) == 0 && address
[5] >= '8' && address
[6] == '.')
130 /* RFC 1918 non-public address space */
131 else if (strncmp(address
, "192.168", 7) == 0)
133 /* RFC 3330 Zeroconf network */
134 else if (strncmp(address
, "169.254", 7) == 0)
135 /*!\note Better score than a test network, but not quite as good as RFC 1918
136 * address space. The reason is that some Linux distributions automatically
137 * configure a Zeroconf address before trying DHCP, so we want to prefer a
138 * DHCP lease to a Zeroconf address.
141 /* RFC 3330 Test network */
142 else if (strncmp(address
, "192.0.2.", 8) == 0)
144 /* Every other address should be publically routable */
148 if (score
> *best_score
) {
150 memcpy(best_addr
, &sin
->sin_addr
, sizeof(*best_addr
));
154 static int get_local_address(struct in_addr
*ourip
)
158 struct lifreq
*ifr
= NULL
;
161 struct sockaddr_in
*sa
;
165 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(__Darwin__)
166 struct ifaddrs
*ifap
, *ifaphead
;
168 const struct sockaddr_in
*sin
;
169 #endif /* BSD_OR_LINUX */
170 struct in_addr best_addr
;
171 int best_score
= -100;
172 memset(&best_addr
, 0, sizeof(best_addr
));
174 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(__Darwin__)
175 rtnerr
= getifaddrs(&ifaphead
);
180 #endif /* BSD_OR_LINUX */
182 s
= socket(AF_INET
, SOCK_STREAM
, 0);
185 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(__Darwin__)
186 for (ifap
= ifaphead
; ifap
; ifap
= ifap
->ifa_next
) {
188 if (ifap
->ifa_addr
&& ifap
->ifa_addr
->sa_family
== AF_INET
) {
189 sin
= (const struct sockaddr_in
*) ifap
->ifa_addr
;
190 score_address(sin
, &best_addr
, &best_score
);
197 #endif /* BSD_OR_LINUX */
199 /* There is no reason whatsoever that this shouldn't work on Linux or BSD also. */
201 /* Get a count of interfaces on the machine */
202 ifn
.lifn_family
= AF_INET
;
205 if (ioctl(s
, SIOCGLIFNUM
, &ifn
) < 0) {
210 bufsz
= ifn
.lifn_count
* sizeof(struct lifreq
);
211 if (!(buf
= malloc(bufsz
))) {
215 memset(buf
, 0, bufsz
);
217 /* Get a list of interfaces on the machine */
218 ifc
.lifc_len
= bufsz
;
220 ifc
.lifc_family
= AF_INET
;
222 if (ioctl(s
, SIOCGLIFCONF
, &ifc
) < 0) {
228 for (ifr
= ifc
.lifc_req
, x
= 0; x
< ifn
.lifn_count
; ifr
++, x
++) {
229 sa
= (struct sockaddr_in
*)&(ifr
->lifr_addr
);
230 score_address(sa
, &best_addr
, &best_score
);
242 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(__Darwin__)
243 freeifaddrs(ifaphead
);
244 #endif /* BSD_OR_LINUX */
246 if (res
== 0 && ourip
)
247 memcpy(ourip
, &best_addr
, sizeof(*ourip
));
250 #endif /* HAVE_GETIFADDRS */
252 /* Free HA structure */
253 void ast_free_ha(struct ast_ha
*ha
)
263 /* Copy HA structure */
264 static void ast_copy_ha(struct ast_ha
*from
, struct ast_ha
*to
)
266 memcpy(&to
->netaddr
, &from
->netaddr
, sizeof(from
->netaddr
));
267 memcpy(&to
->netmask
, &from
->netmask
, sizeof(from
->netmask
));
268 to
->sense
= from
->sense
;
271 /* Create duplicate of ha structure */
272 static struct ast_ha
*ast_duplicate_ha(struct ast_ha
*original
)
274 struct ast_ha
*new_ha
;
276 if ((new_ha
= ast_malloc(sizeof(*new_ha
)))) {
277 /* Copy from original to new object */
278 ast_copy_ha(original
, new_ha
);
284 /* Create duplicate HA link list */
285 /* Used in chan_sip2 templates */
286 struct ast_ha
*ast_duplicate_ha_list(struct ast_ha
*original
)
288 struct ast_ha
*start
= original
;
289 struct ast_ha
*ret
= NULL
;
290 struct ast_ha
*link
, *prev
= NULL
;
293 link
= ast_duplicate_ha(start
); /* Create copy of this object */
295 prev
->next
= link
; /* Link previous to this object */
298 ret
= link
; /* Save starting point */
300 start
= start
->next
; /* Go to next object */
301 prev
= link
; /* Save pointer to this object */
303 return ret
; /* Return start of list */
306 struct ast_ha
*ast_append_ha(char *sense
, char *stuff
, struct ast_ha
*path
)
309 char *nm
= "255.255.255.255";
311 struct ast_ha
*prev
= NULL
;
321 if ((ha
= ast_malloc(sizeof(*ha
)))) {
322 ast_copy_string(tmp
, stuff
, sizeof(tmp
));
323 nm
= strchr(tmp
, '/');
325 nm
= "255.255.255.255";
330 if (!strchr(nm
, '.')) {
331 if ((sscanf(nm
, "%d", &x
) == 1) && (x
>= 0) && (x
<= 32)) {
333 for (z
= 0; z
< x
; z
++) {
337 ha
->netmask
.s_addr
= htonl(y
);
339 } else if (!inet_aton(nm
, &ha
->netmask
)) {
340 ast_log(LOG_WARNING
, "%s is not a valid netmask\n", nm
);
344 if (!inet_aton(tmp
, &ha
->netaddr
)) {
345 ast_log(LOG_WARNING
, "%s is not a valid IP\n", tmp
);
349 ha
->netaddr
.s_addr
&= ha
->netmask
.s_addr
;
350 if (!strncasecmp(sense
, "p", 1)) {
351 ha
->sense
= AST_SENSE_ALLOW
;
353 ha
->sense
= AST_SENSE_DENY
;
363 ast_log(LOG_DEBUG
, "%s/%s appended to acl for peer\n", stuff
, nm
);
367 int ast_apply_ha(struct ast_ha
*ha
, struct sockaddr_in
*sin
)
369 /* Start optimistic */
370 int res
= AST_SENSE_ALLOW
;
372 char iabuf
[INET_ADDRSTRLEN
];
373 char iabuf2
[INET_ADDRSTRLEN
];
375 ast_copy_string(iabuf
, ast_inet_ntoa(sin
->sin_addr
), sizeof(iabuf
));
376 ast_copy_string(iabuf2
, ast_inet_ntoa(ha
->netaddr
), sizeof(iabuf2
));
378 ast_log(LOG_DEBUG
, "##### Testing %s with %s\n", iabuf
, iabuf2
);
379 /* For each rule, if this address and the netmask = the net address
380 apply the current rule */
381 if ((sin
->sin_addr
.s_addr
& ha
->netmask
.s_addr
) == ha
->netaddr
.s_addr
)
388 int ast_get_ip_or_srv(struct sockaddr_in
*sin
, const char *value
, const char *service
)
391 struct ast_hostent ahp
;
394 int tportno
= ntohs(sin
->sin_port
);
395 if (inet_aton(value
, &sin
->sin_addr
))
398 snprintf(srv
, sizeof(srv
), "%s.%s", service
, value
);
399 if (ast_get_srv(NULL
, host
, sizeof(host
), &tportno
, srv
) > 0) {
400 sin
->sin_port
= htons(tportno
);
404 hp
= ast_gethostbyname(value
, &ahp
);
406 memcpy(&sin
->sin_addr
, hp
->h_addr
, sizeof(sin
->sin_addr
));
408 ast_log(LOG_WARNING
, "Unable to lookup '%s'\n", value
);
414 struct dscp_codepoint
{
419 /* IANA registered DSCP codepoints */
421 static const struct dscp_codepoint dscp_pool1
[] = {
445 int ast_str2tos(const char *value
, unsigned int *tos
)
450 if (sscanf(value
, "%i", &fval
) == 1) {
455 for (x
= 0; x
< sizeof(dscp_pool1
) / sizeof(dscp_pool1
[0]); x
++) {
456 if (!strcasecmp(value
, dscp_pool1
[x
].name
)) {
457 *tos
= dscp_pool1
[x
].space
<< 2;
462 if (!strcasecmp(value
, "lowdelay"))
463 *tos
= IPTOS_LOWDELAY
;
464 else if (!strcasecmp(value
, "throughput"))
465 *tos
= IPTOS_THROUGHPUT
;
466 else if (!strcasecmp(value
, "reliability"))
467 *tos
= IPTOS_RELIABILITY
;
468 else if (!strcasecmp(value
, "mincost"))
469 *tos
= IPTOS_MINCOST
;
470 else if (!strcasecmp(value
, "none"))
475 ast_log(LOG_WARNING
, "TOS value %s is deprecated. Please see doc/ip-tos.txt for more information.\n", value
);
480 const char *ast_tos2str(unsigned int tos
)
489 case IPTOS_THROUGHPUT
:
491 case IPTOS_RELIABILITY
:
492 return "reliability";
496 for (x
= 0; x
< sizeof(dscp_pool1
) / sizeof(dscp_pool1
[0]); x
++) {
497 if (dscp_pool1
[x
].space
== (tos
>> 2))
498 return dscp_pool1
[x
].name
;
505 int ast_get_ip(struct sockaddr_in
*sin
, const char *value
)
507 return ast_get_ip_or_srv(sin
, value
, NULL
);
510 /* iface is the interface (e.g. eth0); address is the return value */
511 int ast_lookup_iface(char *iface
, struct in_addr
*address
)
514 struct my_ifreq ifreq
;
516 memset(&ifreq
, 0, sizeof(ifreq
));
517 ast_copy_string(ifreq
.ifrn_name
, iface
, sizeof(ifreq
.ifrn_name
));
519 mysock
= socket(PF_INET
, SOCK_DGRAM
, IPPROTO_IP
);
520 res
= ioctl(mysock
, SIOCGIFADDR
, &ifreq
);
524 ast_log(LOG_WARNING
, "Unable to get IP of %s: %s\n", iface
, strerror(errno
));
525 memcpy((char *)address
, (char *)&__ourip
, sizeof(__ourip
));
528 memcpy((char *)address
, (char *)&ifreq
.ifru_addr
.sin_addr
, sizeof(ifreq
.ifru_addr
.sin_addr
));
533 int ast_ouraddrfor(struct in_addr
*them
, struct in_addr
*us
)
536 struct sockaddr_in sin
;
539 s
= socket(PF_INET
, SOCK_DGRAM
, 0);
541 ast_log(LOG_WARNING
, "Cannot create socket\n");
544 sin
.sin_family
= AF_INET
;
546 sin
.sin_addr
= *them
;
547 if (connect(s
, (struct sockaddr
*)&sin
, sizeof(sin
))) {
548 ast_log(LOG_WARNING
, "Cannot connect\n");
553 if (getsockname(s
, (struct sockaddr
*)&sin
, &slen
)) {
554 ast_log(LOG_WARNING
, "Cannot get socket name\n");
563 int ast_find_ourip(struct in_addr
*ourip
, struct sockaddr_in bindaddr
)
565 char ourhost
[MAXHOSTNAMELEN
] = "";
566 struct ast_hostent ahp
;
568 struct in_addr saddr
;
570 /* just use the bind address if it is nonzero */
571 if (ntohl(bindaddr
.sin_addr
.s_addr
)) {
572 memcpy(ourip
, &bindaddr
.sin_addr
, sizeof(*ourip
));
575 /* try to use our hostname */
576 if (gethostname(ourhost
, sizeof(ourhost
) - 1)) {
577 ast_log(LOG_WARNING
, "Unable to get hostname\n");
579 hp
= ast_gethostbyname(ourhost
, &ahp
);
581 memcpy(ourip
, hp
->h_addr
, sizeof(*ourip
));
585 /* A.ROOT-SERVERS.NET. */
586 if (inet_aton("198.41.0.4", &saddr
) && !ast_ouraddrfor(&saddr
, ourip
))
588 return get_local_address(ourip
);