Newer
Older
* Asterisk -- An open source telephony toolkit.
Kevin P. Fleming
committed
* Copyright (C) 1999 - 2006, Digium, Inc.
Kevin P. Fleming
committed
* Mark Spencer <markster@digium.com>
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
*
* \brief Various sorts of access control
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/ioctl.h>
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
#include <net/route.h>
#endif
#include <sys/sockio.h>
#endif
/* netinet/ip.h may not define the following (See RFCs 791 and 1349) */
#if !defined(IPTOS_LOWCOST)
#endif
#if !defined(IPTOS_MINCOST)
#define IPTOS_MINCOST IPTOS_LOWCOST
#endif
#include "asterisk/acl.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/options.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "asterisk/srv.h"
struct ast_ha {
/* Host access rule */
struct in_addr netaddr;
struct in_addr netmask;
int sense;
struct ast_ha *next;
};
/* Default IP - if not otherwise set, don't breathe garbage */
struct my_ifreq {
char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. "eth0", "ppp0", etc. */
struct sockaddr_in ifru_addr;
};
void ast_free_ha(struct ast_ha *ha)
{
struct ast_ha *hal;
while(ha) {
hal = ha;
ha = ha->next;
free(hal);
}
}
/* Copy HA structure */
static void ast_copy_ha(struct ast_ha *from, struct ast_ha *to)
{
memcpy(&to->netaddr, &from->netaddr, sizeof(from->netaddr));
memcpy(&to->netmask, &from->netmask, sizeof(from->netmask));
to->sense = from->sense;
}
/* Create duplicate of ha structure */
static struct ast_ha *ast_duplicate_ha(struct ast_ha *original)
{
struct ast_ha *new_ha;
if ((new_ha = ast_malloc(sizeof(*new_ha)))) {
/* Copy from original to new object */
ast_copy_ha(original, new_ha);
}
}
/* Create duplicate HA link list */
/* Used in chan_sip2 templates */
struct ast_ha *ast_duplicate_ha_list(struct ast_ha *original)
{
struct ast_ha *start=original;
struct ast_ha *ret = NULL;
struct ast_ha *link,*prev=NULL;
link = ast_duplicate_ha(start); /* Create copy of this object */
if (prev)
prev->next = link; /* Link previous to this object */
ret = link; /* Save starting point */
start = start->next; /* Go to next object */
prev = link; /* Save pointer to this object */
}
return ret; /* Return start of list */
struct ast_ha *ast_append_ha(char *sense, char *stuff, struct ast_ha *path)
{
struct ast_ha *ha;
struct ast_ha *prev = NULL;
struct ast_ha *ret;
if ((ha = ast_malloc(sizeof(*ha)))) {
ast_copy_string(tmp, stuff, sizeof(tmp));
nm = strchr(tmp, '/');
*nm = '\0';
nm++;
}
if (!strchr(nm, '.')) {
Kevin P. Fleming
committed
if ((sscanf(nm, "%d", &x) == 1) && (x >= 0) && (x <= 32)) {
y = 0;
for (z=0;z<x;z++) {
y >>= 1;
}
ha->netmask.s_addr = htonl(y);
}
} else if (!inet_aton(nm, &ha->netmask)) {
ast_log(LOG_WARNING, "%s is not a valid netmask\n", nm);
if (!inet_aton(tmp, &ha->netaddr)) {
ast_log(LOG_WARNING, "%s is not a valid IP\n", tmp);
}
ha->netaddr.s_addr &= ha->netmask.s_addr;
if (!strncasecmp(sense, "p", 1)) {
ha->sense = AST_SENSE_ALLOW;
} else {
ha->sense = AST_SENSE_DENY;
}
ha->next = NULL;
ast_log(LOG_DEBUG, "%s/%s appended to acl for peer\n", stuff, nm);
}
int ast_apply_ha(struct ast_ha *ha, struct sockaddr_in *sin)
{
/* Start optimistic */
int res = AST_SENSE_ALLOW;
char iabuf[INET_ADDRSTRLEN];
char iabuf2[INET_ADDRSTRLEN];
ast_log(LOG_DEBUG,
"##### Testing %s with %s\n",
ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr),
ast_inet_ntoa(iabuf2, sizeof(iabuf2), ha->netaddr));
/* For each rule, if this address and the netmask = the net address
apply the current rule */
if ((sin->sin_addr.s_addr & ha->netmask.s_addr) == ha->netaddr.s_addr)
res = ha->sense;
ha = ha->next;
}
return res;
}
int ast_get_ip_or_srv(struct sockaddr_in *sin, const char *value, const char *service)
char srv[256];
char host[256];
int tportno = ntohs(sin->sin_port);
if (inet_aton(value, &sin->sin_addr))
return 0;
if (service) {
snprintf(srv, sizeof(srv), "%s.%s", service, value);
if (ast_get_srv(NULL, host, sizeof(host), &tportno, srv) > 0) {
sin->sin_port = htons(tportno);
value = host;
}
}
hp = ast_gethostbyname(value, &ahp);
if (hp) {
memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
} else {
ast_log(LOG_WARNING, "Unable to lookup '%s'\n", value);
return -1;
}
return 0;
}
Kevin P. Fleming
committed
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
struct dscp_codepoint {
char *name;
unsigned int space;
};
/* IANA registered DSCP codepoints */
static const struct dscp_codepoint dscp_pool1[] = {
{ "CS0", 0x00 },
{ "CS1", 0x08 },
{ "CS2", 0x10 },
{ "CS3", 0x18 },
{ "CS4", 0x20 },
{ "CS5", 0x28 },
{ "CS6", 0x30 },
{ "CS7", 0x38 },
{ "AF11", 0x0A },
{ "AF12", 0x0C },
{ "AF13", 0x0E },
{ "AF21", 0x12 },
{ "AF22", 0x14 },
{ "AF23", 0x16 },
{ "AF31", 0x1A },
{ "AF32", 0x1C },
{ "AF33", 0x1E },
{ "AF41", 0x22 },
{ "AF42", 0x24 },
{ "AF43", 0x26 },
{ "EF", 0x2E },
};
int ast_str2tos(const char *value, unsigned int *tos)
Kevin P. Fleming
committed
unsigned int x;
if (sscanf(value, "%i", &fval) == 1) {
*tos = fval & 0xFF;
return 0;
}
for (x = 0; x < sizeof(dscp_pool1) / sizeof(dscp_pool1[0]); x++) {
if (!strcasecmp(value, dscp_pool1[x].name)) {
*tos = dscp_pool1[x].space << 2;
return 0;
}
}
if (!strcasecmp(value, "lowdelay"))
*tos = IPTOS_LOWDELAY;
else if (!strcasecmp(value, "throughput"))
*tos = IPTOS_THROUGHPUT;
else if (!strcasecmp(value, "reliability"))
*tos = IPTOS_RELIABILITY;
else if (!strcasecmp(value, "mincost"))
*tos = IPTOS_MINCOST;
else if (!strcasecmp(value, "none"))
*tos = 0;
else
return -1;
Kevin P. Fleming
committed
ast_log(LOG_WARNING, "TOS value %s is deprecated. Please see doc/ip-tos.txt for more information.\n", value);
Kevin P. Fleming
committed
Kevin P. Fleming
committed
const char *ast_tos2str(unsigned int tos)
{
unsigned int x;
switch (tos) {
case 0:
return "none";
case IPTOS_LOWDELAY:
return "lowdelay";
case IPTOS_THROUGHPUT:
return "throughput";
case IPTOS_RELIABILITY:
return "reliability";
case IPTOS_MINCOST:
return "mincost";
default:
for (x = 0; x < sizeof(dscp_pool1) / sizeof(dscp_pool1[0]); x++) {
if (dscp_pool1[x].space == (tos >> 2))
return dscp_pool1[x].name;
}
}
return "unknown";
}
int ast_get_ip(struct sockaddr_in *sin, const char *value)
{
return ast_get_ip_or_srv(sin, value, NULL);
}
/* iface is the interface (e.g. eth0); address is the return value */
int ast_lookup_iface(char *iface, struct in_addr *address)
{
int mysock, res = 0;
struct my_ifreq ifreq;
memset(&ifreq, 0, sizeof(ifreq));
ast_copy_string(ifreq.ifrn_name, iface, sizeof(ifreq.ifrn_name));
mysock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
res = ioctl(mysock, SIOCGIFADDR, &ifreq);
close(mysock);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to get IP of %s: %s\n", iface, strerror(errno));
memcpy((char *)address, (char *)&__ourip, sizeof(__ourip));
memcpy((char *)address, (char *)&ifreq.ifru_addr.sin_addr, sizeof(ifreq.ifru_addr.sin_addr));
return 0;
}
}
int ast_ouraddrfor(struct in_addr *them, struct in_addr *us)
{
int s;
struct sockaddr_in sin;
socklen_t slen;
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
ast_log(LOG_WARNING, "Cannot create socket\n");
sin.sin_family = AF_INET;
sin.sin_port = 5060;
sin.sin_addr = *them;
if (connect(s, (struct sockaddr *)&sin, sizeof(sin))) {
ast_log(LOG_WARNING, "Cannot connect\n");
slen = sizeof(sin);
if (getsockname(s, (struct sockaddr *)&sin, &slen)) {
ast_log(LOG_WARNING, "Cannot get socket name\n");
int ast_find_ourip(struct in_addr *ourip, struct sockaddr_in bindaddr)
{
struct ast_hostent ahp;
struct hostent *hp;
struct in_addr saddr;
/* just use the bind address if it is nonzero */
if (ntohl(bindaddr.sin_addr.s_addr)) {
memcpy(ourip, &bindaddr.sin_addr, sizeof(*ourip));
return 0;
}
/* try to use our hostname */
if (gethostname(ourhost, sizeof(ourhost) - 1)) {
ast_log(LOG_WARNING, "Unable to get hostname\n");
} else {
hp = ast_gethostbyname(ourhost, &ahp);
if (hp) {
memcpy(ourip, hp->h_addr, sizeof(*ourip));
return 0;
}
}
/* A.ROOT-SERVERS.NET. */
if (inet_aton("198.41.0.4", &saddr) && !ast_ouraddrfor(&saddr, ourip))
return 0;
return -1;
}