Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

acl.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- A telephony toolkit for Linux.
00003  *
00004  * Various sorts of access control
00005  * 
00006  * Copyright (C) 1999, Mark Spencer
00007  *
00008  * Mark Spencer <markster@linux-support.net>
00009  *
00010  * This program is free software, distributed under the terms of
00011  * the GNU General Public License
00012  */
00013 
00014 #include <stdio.h>
00015 #include <stdlib.h>
00016 #include <pthread.h>
00017 #include <string.h>
00018 #include <sys/time.h>
00019 #include <signal.h>
00020 #include <errno.h>
00021 #include <unistd.h>
00022 #include <asterisk/acl.h>
00023 #include <asterisk/logger.h>
00024 #include <asterisk/channel.h>
00025 #include <arpa/inet.h>
00026 #include <sys/socket.h>
00027 #include <netdb.h>
00028 #include <net/if.h>
00029 #include <netinet/in_systm.h>
00030 #include <netinet/ip.h>
00031 #include <sys/ioctl.h>
00032 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
00033 #include <fcntl.h>
00034 #include <net/route.h>
00035 
00036 static ast_mutex_t routeseq_lock = AST_MUTEX_INITIALIZER;
00037 #endif
00038 
00039 #define AST_SENSE_DENY        0
00040 #define AST_SENSE_ALLOW       1
00041 
00042 struct ast_ha {
00043    /* Host access rule */
00044    struct in_addr netaddr;
00045    struct in_addr netmask;
00046    int sense;
00047    struct ast_ha *next;
00048 };
00049 
00050 /* Default IP - if not otherwise set, don't breathe garbage */
00051 static struct in_addr __ourip = { 0x00000000 };
00052 
00053 struct my_ifreq {
00054    char ifrn_name[IFNAMSIZ];  /* Interface name, e.g. "eth0", "ppp0", etc.  */
00055    struct sockaddr_in ifru_addr;
00056 };
00057 
00058 void ast_free_ha(struct ast_ha *ha)
00059 {
00060    struct ast_ha *hal;
00061    while(ha) {
00062       hal = ha;
00063       ha = ha->next;
00064       free(hal);
00065    }
00066 }
00067 
00068 struct ast_ha *ast_append_ha(char *sense, char *stuff, struct ast_ha *path)
00069 {
00070    struct ast_ha *ha = malloc(sizeof(struct ast_ha));
00071    char *nm;
00072    char tmp[256] = "";
00073    struct ast_ha *prev = NULL;
00074    struct ast_ha *ret;
00075    int x,z;
00076    unsigned int y;
00077    ret = path;
00078    while(path) {
00079       prev = path;
00080       path = path->next;
00081    }
00082    if (ha) {
00083       strncpy(tmp, stuff, sizeof(tmp) - 1);
00084       nm = strchr(tmp, '/');
00085       if (!nm)
00086          nm = "255.255.255.255";
00087       else {
00088          *nm = '\0';
00089          nm++;
00090       }
00091       if (!strchr(nm, '.')) {
00092          if ((sscanf(nm, "%i", &x) == 1) && (x >= 0) && (x <= 32)) {
00093             y = 0;
00094             for (z=0;z<x;z++) {
00095                y >>= 1;
00096                y |= 0x80000000;
00097             }
00098             ha->netmask.s_addr = htonl(y);
00099          }
00100       } else if (!inet_aton(nm, &ha->netmask)) {
00101          ast_log(LOG_WARNING, "%s not a valid netmask\n", nm);
00102          free(ha);
00103          return path;
00104       }
00105       if (!inet_aton(tmp, &ha->netaddr)) {
00106          ast_log(LOG_WARNING, "%s not a valid IP\n", tmp);
00107          free(ha);
00108          return path;
00109       }
00110       ha->netaddr.s_addr &= ha->netmask.s_addr;
00111       if (!strncasecmp(sense, "p", 1)) {
00112          ha->sense = AST_SENSE_ALLOW;
00113       } else {
00114          ha->sense = AST_SENSE_DENY;
00115       }
00116       ha->next = NULL;
00117       if (prev)
00118          prev->next = ha;
00119       else
00120          ret = ha;
00121    }
00122    return ret;
00123 }
00124 
00125 int ast_apply_ha(struct ast_ha *ha, struct sockaddr_in *sin)
00126 {
00127    /* Start optimistic */
00128    int res = AST_SENSE_ALLOW;
00129    while(ha) {
00130       /* For each rule, if this address and the netmask = the net address
00131          apply the current rule */
00132       if ((sin->sin_addr.s_addr & ha->netmask.s_addr) == (ha->netaddr.s_addr))
00133          res = ha->sense;
00134       ha = ha->next;
00135    }
00136    return res;
00137 }
00138 
00139 int ast_get_ip(struct sockaddr_in *sin, char *value)
00140 {
00141    struct hostent *hp;
00142    hp = gethostbyname(value);
00143    if (hp) {
00144       memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
00145    } else {
00146       ast_log(LOG_WARNING, "Unable to lookup '%s'\n", value);
00147       return -1;
00148    }
00149    return 0;
00150 }
00151 
00152 int inaddrcmp(struct sockaddr_in *sin1, struct sockaddr_in *sin2)
00153 {
00154    return ((sin1->sin_addr.s_addr != sin2->sin_addr.s_addr )
00155          || (sin1->sin_port != sin2->sin_port));
00156 }
00157 
00158 /* iface is the interface (e.g. eth0); address is the return value */
00159 int ast_lookup_iface(char *iface, struct in_addr *address) {
00160    int mysock, res = 0;
00161    struct my_ifreq ifreq;
00162 
00163    memset(&ifreq, 0, sizeof(ifreq));
00164    strncpy(ifreq.ifrn_name,iface,sizeof(ifreq.ifrn_name) - 1);
00165 
00166    mysock = socket(PF_INET,SOCK_DGRAM,IPPROTO_IP);
00167    res = ioctl(mysock,SIOCGIFADDR,&ifreq);
00168 
00169    close(mysock);
00170    if (res < 0) {
00171       ast_log(LOG_WARNING, "Unable to get IP of %s: %s\n", iface, strerror(errno));
00172       memcpy((char *)address,(char *)&__ourip,sizeof(__ourip));
00173       return -1;
00174    } else {
00175       memcpy((char *)address,(char *)&ifreq.ifru_addr.sin_addr,sizeof(ifreq.ifru_addr.sin_addr));
00176       return 0;
00177    }
00178 }
00179 
00180 int ast_ouraddrfor(struct in_addr *them, struct in_addr *us)
00181 {
00182 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
00183    struct sockaddr_in *sin;
00184    struct sockaddr *sa;
00185    struct {
00186       struct   rt_msghdr m_rtm;
00187       char  m_space[512];
00188    } m_rtmsg;
00189    char *cp, *p = ast_strdupa(inet_ntoa(*them));
00190    int i, l, s, seq, flags;
00191    pid_t pid = getpid();
00192    static int routeseq; /* Protected by "routeseq_lock" mutex */
00193 
00194    memset(us, 0, sizeof(struct in_addr));
00195 
00196    memset(&m_rtmsg, 0, sizeof(m_rtmsg));
00197    m_rtmsg.m_rtm.rtm_type = RTM_GET;
00198    m_rtmsg.m_rtm.rtm_flags = RTF_UP | RTF_HOST;
00199    m_rtmsg.m_rtm.rtm_version = RTM_VERSION;
00200    ast_mutex_lock(&routeseq_lock);
00201    seq = ++routeseq;
00202    ast_mutex_unlock(&routeseq_lock);
00203    m_rtmsg.m_rtm.rtm_seq = seq;
00204    m_rtmsg.m_rtm.rtm_addrs = RTA_IFA | RTA_DST;
00205    m_rtmsg.m_rtm.rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in);
00206    sin = (struct sockaddr_in *)m_rtmsg.m_space;
00207    sin->sin_family = AF_INET;
00208    sin->sin_len = sizeof(struct sockaddr_in);
00209    sin->sin_addr = *them;
00210 
00211    if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
00212       ast_log(LOG_ERROR, "Error opening routing socket\n");
00213       return -1;
00214    }
00215    flags = fcntl(s, F_GETFL);
00216    fcntl(s, F_SETFL, flags | O_NONBLOCK);
00217    if (write(s, (char *)&m_rtmsg, m_rtmsg.m_rtm.rtm_msglen) < 0) {
00218       ast_log(LOG_ERROR, "Error writing to routing socket: %s\n", strerror(errno));
00219       close(s);
00220       return -1;
00221    }
00222    do {
00223       l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
00224    } while (l > 0 && (m_rtmsg.m_rtm.rtm_seq != 1 || m_rtmsg.m_rtm.rtm_pid != pid));
00225    if (l < 0) {
00226       if (errno != EAGAIN)
00227          ast_log(LOG_ERROR, "Error reading from routing socket\n");
00228       close(s);
00229       return -1;
00230    }
00231    close(s);
00232 
00233    if (m_rtmsg.m_rtm.rtm_version != RTM_VERSION) {
00234       ast_log(LOG_ERROR, "Unsupported route socket protocol version\n");
00235       return -1;
00236    }
00237 
00238    if (m_rtmsg.m_rtm.rtm_msglen != l)
00239       ast_log(LOG_WARNING, "Message length mismatch, in packet %d, returned %d\n",
00240             m_rtmsg.m_rtm.rtm_msglen, l);
00241 
00242    if (m_rtmsg.m_rtm.rtm_errno) {
00243       ast_log(LOG_ERROR, "RTM_GET got %s (%d)\n",
00244             strerror(m_rtmsg.m_rtm.rtm_errno), m_rtmsg.m_rtm.rtm_errno);
00245       return -1;
00246    }
00247 
00248    cp = (char *)m_rtmsg.m_space;
00249    if (m_rtmsg.m_rtm.rtm_addrs)
00250       for (i = 1; i; i <<= 1)
00251          if (m_rtmsg.m_rtm.rtm_addrs & i) {
00252             sa = (struct sockaddr *)cp;
00253             if (i == RTA_IFA && sa->sa_family == AF_INET) {
00254                sin = (struct sockaddr_in *)sa;
00255                *us = sin->sin_addr;
00256                ast_log(LOG_DEBUG, "Found route to %s, output from our address %s.\n", p, inet_ntoa(*us));
00257                return 0;
00258             }
00259             cp += sa->sa_len > 0 ?
00260                  (1 + ((sa->sa_len - 1) | (sizeof(long) - 1))) :
00261                  sizeof(long);
00262          }
00263 
00264    ast_log(LOG_DEBUG, "No route found for address %s!\n", p);
00265    return -1;
00266 #else
00267    FILE *PROC;
00268    unsigned int remote_ip;
00269    int res = 1;
00270    char line[256];
00271    remote_ip = them->s_addr;
00272    
00273    PROC = fopen("/proc/net/route","r");
00274    if (!PROC) {
00275       bzero(us,sizeof(struct in_addr));
00276       return -1;
00277    }
00278    /* First line contains headers */
00279    fgets(line,sizeof(line),PROC);
00280 
00281    while (!feof(PROC)) {
00282       char iface[8];
00283       unsigned int dest, gateway, mask;
00284       int i,fieldnum;
00285       char *fields[40];
00286 
00287       fgets(line,sizeof(line),PROC);
00288 
00289       fieldnum = 0;
00290       for (i=0;i<sizeof(line);i++) {
00291          char *offset;
00292 
00293          fields[fieldnum++] = line + i;
00294          offset = strchr(line + i,'\t');
00295          if (offset == NULL) {
00296             /* Exit loop */
00297             break;
00298          } else if (fieldnum >= 9) {
00299             /* Short-circuit: can't break at 8, since the end of field 7 is figured when fieldnum=8 */
00300             break;
00301          } else {
00302             *offset = '\0';
00303             i = offset - line;
00304          }
00305       }
00306 
00307       sscanf(fields[0],"%s",iface);
00308       sscanf(fields[1],"%x",&dest);
00309       sscanf(fields[2],"%x",&gateway);
00310       sscanf(fields[7],"%x",&mask);
00311 #if 0
00312       printf("Addr: %s %08x Dest: %08x Mask: %08x\n", inet_ntoa(*them), remote_ip, dest, mask);
00313 #endif      
00314       /* Looks simple, but here is the magic */
00315       if (((remote_ip & mask) ^ dest) == 0) {
00316          res = ast_lookup_iface(iface,us);
00317          break;
00318       }
00319    }
00320    fclose(PROC);
00321    if (res == 1) {
00322       ast_log(LOG_WARNING, "Yikes!  No default route?!!\n");
00323       bzero(us,sizeof(struct in_addr));
00324       return -2;
00325    } else if (res) {
00326       /* We've already warned in subroutine */
00327       return -1;
00328    }
00329    return 0;
00330 #endif
00331 }

Generated on Fri Feb 27 12:19:40 2004 for Asterisk by doxygen 1.3.5