4d6fcdc5210e033e845f1ac4119ef438bbe7a7a5
[asterisk/asterisk.git] / acl.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Various sorts of access control
5  * 
6  * Copyright (C) 1999-2005, Digium, Inc.
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/time.h>
18 #include <signal.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <sys/socket.h>
24 #include <netdb.h>
25 #include <net/if.h>
26 #include <netinet/in.h>
27 #include <netinet/in_systm.h>
28 #include <netinet/ip.h>
29 #include <sys/ioctl.h>
30
31 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
32 #include <fcntl.h>
33 #include <net/route.h>
34 #endif
35
36 #if defined (SOLARIS) || defined(__OpenBSD__)
37 #include <sys/sockio.h>
38 /* netinet/ip.h does not define the following (See RFCs 791 and 1349) */
39 #define       IPTOS_LOWCOST           0x02
40 #define       IPTOS_MINCOST           IPTOS_LOWCOST
41 #endif
42
43 #include "asterisk.h"
44
45 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
46
47 #include "asterisk/acl.h"
48 #include "asterisk/logger.h"
49 #include "asterisk/channel.h"
50 #include "asterisk/options.h"
51 #include "asterisk/utils.h"
52 #include "asterisk/lock.h"
53 #include "asterisk/srv.h"
54
55 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
56 AST_MUTEX_DEFINE_STATIC(routeseq_lock);
57 #endif
58
59 struct ast_ha {
60         /* Host access rule */
61         struct in_addr netaddr;
62         struct in_addr netmask;
63         int sense;
64         struct ast_ha *next;
65 };
66
67 /* Default IP - if not otherwise set, don't breathe garbage */
68 static struct in_addr __ourip = { 0x00000000 };
69
70 struct my_ifreq {
71         char ifrn_name[IFNAMSIZ];       /* Interface name, e.g. "eth0", "ppp0", etc.  */
72         struct sockaddr_in ifru_addr;
73 };
74
75 /* Free HA structure */
76 void ast_free_ha(struct ast_ha *ha)
77 {
78         struct ast_ha *hal;
79         while(ha) {
80                 hal = ha;
81                 ha = ha->next;
82                 free(hal);
83         }
84 }
85
86 /* Copy HA structure */
87 static void ast_copy_ha(struct ast_ha *from, struct ast_ha *to)
88 {
89         memcpy(&to->netaddr, &from->netaddr, sizeof(from->netaddr));
90         memcpy(&to->netmask, &from->netmask, sizeof(from->netmask));
91         to->sense = from->sense;
92 }
93
94 /* Create duplicate of ha structure */
95 static struct ast_ha *ast_duplicate_ha(struct ast_ha *original)
96 {
97         struct ast_ha *new_ha = malloc(sizeof(struct ast_ha));
98         /* Copy from original to new object */
99         ast_copy_ha(original, new_ha); 
100
101         return new_ha;
102 }
103
104 /* Create duplicate HA link list */
105 /*  Used in chan_sip2 templates */
106 struct ast_ha *ast_duplicate_ha_list(struct ast_ha *original)
107 {
108         struct ast_ha *start=original;
109         struct ast_ha *ret = NULL;
110         struct ast_ha *link,*prev=NULL;
111
112         while (start) {
113                 link = ast_duplicate_ha(start);  /* Create copy of this object */
114                 if (prev)
115                         prev->next = link;              /* Link previous to this object */
116
117                 if (!ret) 
118                         ret = link;             /* Save starting point */
119
120                 start = start->next;            /* Go to next object */
121                 prev = link;                    /* Save pointer to this object */
122         }
123         return ret;                     /* Return start of list */
124 }
125
126 struct ast_ha *ast_append_ha(char *sense, char *stuff, struct ast_ha *path)
127 {
128         struct ast_ha *ha = malloc(sizeof(struct ast_ha));
129         char *nm = "255.255.255.255";
130         char tmp[256];
131         struct ast_ha *prev = NULL;
132         struct ast_ha *ret;
133         int x, z;
134         unsigned int y;
135         ret = path;
136         while (path) {
137                 prev = path;
138                 path = path->next;
139         }
140         if (ha) {
141                 ast_copy_string(tmp, stuff, sizeof(tmp));
142                 nm = strchr(tmp, '/');
143                 if (!nm) {
144                         nm = "255.255.255.255";
145                 } else {
146                         *nm = '\0';
147                         nm++;
148                 }
149                 if (!strchr(nm, '.')) {
150                         if ((sscanf(nm, "%d", &x) == 1) && (x >= 0) && (x <= 32)) {
151                                 y = 0;
152                                 for (z=0;z<x;z++) {
153                                         y >>= 1;
154                                         y |= 0x80000000;
155                                 }
156                                 ha->netmask.s_addr = htonl(y);
157                         }
158                 } else if (!inet_aton(nm, &ha->netmask)) {
159                         ast_log(LOG_WARNING, "%s is not a valid netmask\n", nm);
160                         free(ha);
161                         return path;
162                 }
163                 if (!inet_aton(tmp, &ha->netaddr)) {
164                         ast_log(LOG_WARNING, "%s is not a valid IP\n", tmp);
165                         free(ha);
166                         return path;
167                 }
168                 ha->netaddr.s_addr &= ha->netmask.s_addr;
169                 if (!strncasecmp(sense, "p", 1)) {
170                         ha->sense = AST_SENSE_ALLOW;
171                 } else {
172                         ha->sense = AST_SENSE_DENY;
173                 }
174                 ha->next = NULL;
175                 if (prev) {
176                         prev->next = ha;
177                 } else {
178                         ret = ha;
179                 }
180         }
181         ast_log(LOG_DEBUG, "%s/%s appended to acl for peer\n", stuff, nm);
182         return ret;
183 }
184
185 int ast_apply_ha(struct ast_ha *ha, struct sockaddr_in *sin)
186 {
187         /* Start optimistic */
188         int res = AST_SENSE_ALLOW;
189         while (ha) {
190                 char iabuf[INET_ADDRSTRLEN];
191                 char iabuf2[INET_ADDRSTRLEN];
192                 /* DEBUG */
193                 ast_log(LOG_DEBUG,
194                         "##### Testing %s with %s\n",
195                         ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr),
196                         ast_inet_ntoa(iabuf2, sizeof(iabuf2), ha->netaddr));
197                 /* For each rule, if this address and the netmask = the net address
198                    apply the current rule */
199                 if ((sin->sin_addr.s_addr & ha->netmask.s_addr) == ha->netaddr.s_addr)
200                         res = ha->sense;
201                 ha = ha->next;
202         }
203         return res;
204 }
205
206 int ast_get_ip_or_srv(struct sockaddr_in *sin, const char *value, const char *service)
207 {
208         struct hostent *hp;
209         struct ast_hostent ahp;
210         char srv[256];
211         char host[256];
212         int tportno = ntohs(sin->sin_port);
213         if (inet_aton(value, &sin->sin_addr))
214                 return 0;
215         if (service) {
216                 snprintf(srv, sizeof(srv), "%s.%s", service, value);
217                 if (ast_get_srv(NULL, host, sizeof(host), &tportno, srv) > 0) {
218                         sin->sin_port = htons(tportno);
219                         value = host;
220                 }
221         }
222         hp = ast_gethostbyname(value, &ahp);
223         if (hp) {
224                 memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
225         } else {
226                 ast_log(LOG_WARNING, "Unable to lookup '%s'\n", value);
227                 return -1;
228         }
229         return 0;
230 }
231
232 int ast_str2tos(const char *value, int *tos)
233 {
234         int fval;
235         if (sscanf(value, "%i", &fval) == 1)
236                 *tos = fval & 0xff;
237         else if (!strcasecmp(value, "lowdelay"))
238                 *tos = IPTOS_LOWDELAY;
239         else if (!strcasecmp(value, "throughput"))
240                 *tos = IPTOS_THROUGHPUT;
241         else if (!strcasecmp(value, "reliability"))
242                 *tos = IPTOS_RELIABILITY;
243         else if (!strcasecmp(value, "mincost"))
244                 *tos = IPTOS_MINCOST;
245         else if (!strcasecmp(value, "none"))
246                 *tos = 0;
247         else
248                 return -1;
249         return 0;
250 }
251
252 int ast_get_ip(struct sockaddr_in *sin, const char *value)
253 {
254         return ast_get_ip_or_srv(sin, value, NULL);
255 }
256
257 /* iface is the interface (e.g. eth0); address is the return value */
258 int ast_lookup_iface(char *iface, struct in_addr *address) 
259 {
260         int mysock, res = 0;
261         struct my_ifreq ifreq;
262
263         memset(&ifreq, 0, sizeof(ifreq));
264         ast_copy_string(ifreq.ifrn_name, iface, sizeof(ifreq.ifrn_name));
265
266         mysock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
267         res = ioctl(mysock, SIOCGIFADDR, &ifreq);
268
269         close(mysock);
270         if (res < 0) {
271                 ast_log(LOG_WARNING, "Unable to get IP of %s: %s\n", iface, strerror(errno));
272                 memcpy((char *)address, (char *)&__ourip, sizeof(__ourip));
273                 return -1;
274         } else {
275                 memcpy((char *)address, (char *)&ifreq.ifru_addr.sin_addr, sizeof(ifreq.ifru_addr.sin_addr));
276                 return 0;
277         }
278 }
279
280 int ast_ouraddrfor(struct in_addr *them, struct in_addr *us)
281 {
282         int s;
283         struct sockaddr_in sin;
284         socklen_t slen;
285
286         s = socket(PF_INET, SOCK_DGRAM, 0);
287         if (s < 0) {
288                 ast_log(LOG_WARNING, "Cannot create socket\n");
289                 return -1;
290         }
291         sin.sin_family = AF_INET;
292         sin.sin_port = 5060;
293         sin.sin_addr = *them;
294         if (connect(s, (struct sockaddr *)&sin, sizeof(sin))) {
295                 ast_log(LOG_WARNING, "Cannot connect\n");
296                 close(s);
297                 return -1;
298         }
299         slen = sizeof(sin);
300         if (getsockname(s, (struct sockaddr *)&sin, &slen)) {
301                 ast_log(LOG_WARNING, "Cannot get socket name\n");
302                 close(s);
303                 return -1;
304         }
305         close(s);
306         *us = sin.sin_addr;
307         return 0;
308 }
309
310 int ast_find_ourip(struct in_addr *ourip, struct sockaddr_in bindaddr)
311 {
312         char ourhost[MAXHOSTNAMELEN] = "";
313         struct ast_hostent ahp;
314         struct hostent *hp;
315         struct in_addr saddr;
316
317         /* just use the bind address if it is nonzero */
318         if (ntohl(bindaddr.sin_addr.s_addr)) {
319                 memcpy(ourip, &bindaddr.sin_addr, sizeof(*ourip));
320                 return 0;
321         }
322         /* try to use our hostname */
323         if (gethostname(ourhost, sizeof(ourhost) - 1)) {
324                 ast_log(LOG_WARNING, "Unable to get hostname\n");
325         } else {
326                 hp = ast_gethostbyname(ourhost, &ahp);
327                 if (hp) {
328                         memcpy(ourip, hp->h_addr, sizeof(*ourip));
329                         return 0;
330                 }
331         }
332         /* A.ROOT-SERVERS.NET. */
333         if (inet_aton("198.41.0.4", &saddr) && !ast_ouraddrfor(&saddr, ourip))
334                 return 0;
335         return -1;
336 }
337