47edeb0f2b7f6fbd441cbb7e897af291d6f2a1ce
[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, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
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 <arpa/inet.h>
22 #include <sys/socket.h>
23 #include <netdb.h>
24 #include <net/if.h>
25 #include <netinet/in_systm.h>
26 #include <netinet/ip.h>
27 #include <sys/ioctl.h>
28
29 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
30 #include <fcntl.h>
31 #include <net/route.h>
32 #endif
33
34 #if defined (SOLARIS)
35 #include <sys/sockio.h>
36 #endif
37
38 #include "asterisk/acl.h"
39 #include "asterisk/logger.h"
40 #include "asterisk/channel.h"
41 #include "asterisk/options.h"
42 #include "asterisk/utils.h"
43 #include "asterisk/lock.h"
44 #include "asterisk/srv.h"
45
46 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
47 AST_MUTEX_DEFINE_STATIC(routeseq_lock);
48 #endif
49
50 struct ast_netsock {
51         ASTOBJ_COMPONENTS(struct ast_netsock);
52         struct sockaddr_in bindaddr;
53         int sockfd;
54         int *ioref;
55         struct io_context *ioc;
56         void *data;
57 };
58
59
60 struct ast_ha {
61         /* Host access rule */
62         struct in_addr netaddr;
63         struct in_addr netmask;
64         int sense;
65         struct ast_ha *next;
66 };
67
68 /* Default IP - if not otherwise set, don't breathe garbage */
69 static struct in_addr __ourip = { 0x00000000 };
70
71 struct my_ifreq {
72         char ifrn_name[IFNAMSIZ];       /* Interface name, e.g. "eth0", "ppp0", etc.  */
73         struct sockaddr_in ifru_addr;
74 };
75
76 /* Free HA structure */
77 void ast_free_ha(struct ast_ha *ha)
78 {
79         struct ast_ha *hal;
80         while(ha) {
81                 hal = ha;
82                 ha = ha->next;
83                 free(hal);
84         }
85 }
86
87 /* Copy HA structure */
88 static void ast_copy_ha(struct ast_ha *from, struct ast_ha *to)
89 {
90         memcpy(&to->netaddr, &from->netaddr, sizeof(from->netaddr));
91         memcpy(&to->netmask, &from->netmask, sizeof(from->netmask));
92         to->sense = from->sense;
93 }
94
95 /* Create duplicate of ha structure */
96 static struct ast_ha *ast_duplicate_ha(struct ast_ha *original)
97 {
98         struct ast_ha *new_ha = malloc(sizeof(struct ast_ha));
99
100         /* Copy from original to new object */
101         ast_copy_ha(original, new_ha); 
102
103         return(new_ha);
104
105 }
106
107 /* Create duplicate HA link list */
108 /*  Used in chan_sip2 templates */
109 struct ast_ha *ast_duplicate_ha_list(struct ast_ha *original)
110 {
111         struct ast_ha *start=original;
112         struct ast_ha *ret = NULL;
113         struct ast_ha *link,*prev=NULL;
114
115         while(start) {
116                 link = ast_duplicate_ha(start);  /* Create copy of this object */
117                 if (prev)
118                         prev->next = link;              /* Link previous to this object */
119
120                 if (!ret) 
121                         ret = link;             /* Save starting point */
122
123                 start = start->next;            /* Go to next object */
124                 prev = link;                    /* Save pointer to this object */
125         }
126         return (ret);                           /* Return start of list */
127 }
128
129 struct ast_ha *ast_append_ha(char *sense, char *stuff, struct ast_ha *path)
130 {
131         struct ast_ha *ha = malloc(sizeof(struct ast_ha));
132         char *nm="255.255.255.255";
133         char tmp[256] = "";
134         struct ast_ha *prev = NULL;
135         struct ast_ha *ret;
136         int x,z;
137         unsigned int y;
138         ret = path;
139         while(path) {
140                 prev = path;
141                 path = path->next;
142         }
143         if (ha) {
144                 strncpy(tmp, stuff, sizeof(tmp) - 1);
145                 nm = strchr(tmp, '/');
146                 if (!nm)
147                         nm = "255.255.255.255";
148                 else {
149                         *nm = '\0';
150                         nm++;
151                 }
152                 if (!strchr(nm, '.')) {
153                         if ((sscanf(nm, "%i", &x) == 1) && (x >= 0) && (x <= 32)) {
154                                 y = 0;
155                                 for (z=0;z<x;z++) {
156                                         y >>= 1;
157                                         y |= 0x80000000;
158                                 }
159                                 ha->netmask.s_addr = htonl(y);
160                         }
161                 } else if (!inet_aton(nm, &ha->netmask)) {
162                         ast_log(LOG_WARNING, "%s is not a valid netmask\n", nm);
163                         free(ha);
164                         return path;
165                 }
166                 if (!inet_aton(tmp, &ha->netaddr)) {
167                         ast_log(LOG_WARNING, "%s is not a valid IP\n", tmp);
168                         free(ha);
169                         return path;
170                 }
171                 ha->netaddr.s_addr &= ha->netmask.s_addr;
172                 if (!strncasecmp(sense, "p", 1)) {
173                         ha->sense = AST_SENSE_ALLOW;
174                 } else {
175                         ha->sense = AST_SENSE_DENY;
176                 }
177                 ha->next = NULL;
178                 if (prev)
179                         prev->next = ha;
180                 else
181                         ret = ha;
182         }
183         ast_log(LOG_DEBUG, "%s/%s appended to acl for peer\n",stuff, nm);
184         return ret;
185 }
186
187 int ast_apply_ha(struct ast_ha *ha, struct sockaddr_in *sin)
188 {
189         /* Start optimistic */
190         int res = AST_SENSE_ALLOW;
191         while(ha) {
192                 char iabuf[INET_ADDRSTRLEN];
193                 char iabuf2[INET_ADDRSTRLEN];
194                 /* DEBUG */
195                 ast_log(LOG_DEBUG,
196                         "##### Testing %s with %s\n",
197                         ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr),
198                         ast_inet_ntoa(iabuf2, sizeof(iabuf2), ha->netaddr));
199                 /* For each rule, if this address and the netmask = the net address
200                    apply the current rule */
201                 if ((sin->sin_addr.s_addr & ha->netmask.s_addr) == (ha->netaddr.s_addr))
202                         res = ha->sense;
203                 ha = ha->next;
204         }
205         return res;
206 }
207
208 int ast_get_ip_or_srv(struct sockaddr_in *sin, const char *value, const char *service)
209 {
210         struct hostent *hp;
211         struct ast_hostent ahp;
212         char srv[256];
213         char host[256];
214         int tportno = ntohs(sin->sin_port);
215         if (inet_aton(value, &sin->sin_addr))
216                 return 0;
217         if (service) {
218                 snprintf(srv, sizeof(srv), "%s.%s", service, value);
219                 if (ast_get_srv(NULL, host, sizeof(host), &tportno, srv) > 0) {
220                         sin->sin_port = htons(tportno);
221                         value = host;
222                 }
223         }
224         hp = ast_gethostbyname(value, &ahp);
225         if (hp) {
226                 memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
227         } else {
228                 ast_log(LOG_WARNING, "Unable to lookup '%s'\n", value);
229                 return -1;
230         }
231         return 0;
232 }
233
234 int ast_get_ip(struct sockaddr_in *sin, const char *value)
235 {
236         return ast_get_ip_or_srv(sin, value, NULL);
237 }
238
239 /* iface is the interface (e.g. eth0); address is the return value */
240 int ast_lookup_iface(char *iface, struct in_addr *address) 
241 {
242         int mysock, res = 0;
243         struct my_ifreq ifreq;
244
245         memset(&ifreq, 0, sizeof(ifreq));
246         strncpy(ifreq.ifrn_name,iface,sizeof(ifreq.ifrn_name) - 1);
247
248         mysock = socket(PF_INET,SOCK_DGRAM,IPPROTO_IP);
249         res = ioctl(mysock,SIOCGIFADDR,&ifreq);
250
251         close(mysock);
252         if (res < 0) {
253                 ast_log(LOG_WARNING, "Unable to get IP of %s: %s\n", iface, strerror(errno));
254                 memcpy((char *)address,(char *)&__ourip,sizeof(__ourip));
255                 return -1;
256         } else {
257                 memcpy((char *)address,(char *)&ifreq.ifru_addr.sin_addr,sizeof(ifreq.ifru_addr.sin_addr));
258                 return 0;
259         }
260 }
261
262 int ast_ouraddrfor(struct in_addr *them, struct in_addr *us)
263 {
264         int s;
265         struct sockaddr_in sin;
266         socklen_t slen;
267
268         s = socket(PF_INET, SOCK_DGRAM, 0);
269         if (s == -1) {
270                 ast_log(LOG_WARNING, "Cannot create socket\n");
271                 return -1;
272         }
273         sin.sin_family = AF_INET;
274         sin.sin_port = 5060;
275         sin.sin_addr = *them;
276         if (connect(s, (struct sockaddr *)&sin, sizeof(sin))) {
277                 ast_log(LOG_WARNING, "Cannot connect\n");
278                 close(s);
279                 return -1;
280         }
281         slen = sizeof(sin);
282         if (getsockname(s, (struct sockaddr *)&sin, &slen)) {
283                 ast_log(LOG_WARNING, "Cannot get socket name\n");
284                 close(s);
285                 return -1;
286         }
287         close(s);
288         *us = sin.sin_addr;
289         return 0;
290 }
291
292 int ast_netsock_sockfd(struct ast_netsock *ns)
293 {
294         if (ns)
295                 return ns->sockfd;
296         return -1;
297 }
298
299 struct ast_netsock *ast_netsock_bindaddr(struct ast_netsock_list *list, struct io_context *ioc, struct sockaddr_in *bindaddr, int tos, ast_io_cb callback, void *data)
300 {
301         int netsocket = -1;
302         int *ioref;
303         char iabuf[INET_ADDRSTRLEN];
304         
305         struct ast_netsock *ns;
306         
307         /* Make a UDP socket */
308         netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
309         
310         if (netsocket < 0) {
311                 ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
312                 return NULL;
313         }
314         if (bind(netsocket,(struct sockaddr *)bindaddr, sizeof(struct sockaddr_in))) {
315                 ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), bindaddr->sin_addr), ntohs(bindaddr->sin_port), strerror(errno));
316                 close(netsocket);
317                 return NULL;
318         }
319         if (option_verbose > 1)
320                 ast_verbose(VERBOSE_PREFIX_2 "Using TOS bits %d\n", tos);
321
322         if (setsockopt(netsocket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos))) 
323                 ast_log(LOG_WARNING, "Unable to set TOS to %d\n", tos);
324
325         ns = malloc(sizeof(struct ast_netsock));
326         if (ns) {
327                 /* Establish I/O callback for socket read */
328                 ioref = ast_io_add(ioc, netsocket, callback, AST_IO_IN, ns);
329                 if (!ioref) {
330                         ast_log(LOG_WARNING, "Out of memory!\n");
331                         close(netsocket);
332                         free(ns);
333                         return NULL;
334                 }       
335                 ASTOBJ_INIT(ns);
336                 ns->ioref = ioref;
337                 ns->ioc = ioc;
338                 ns->sockfd = netsocket;
339                 ns->data = data;
340                 memcpy(&ns->bindaddr, bindaddr, sizeof(ns->bindaddr));
341                 ASTOBJ_CONTAINER_LINK(list, ns);
342         } else {
343                 ast_log(LOG_WARNING, "Out of memory!\n");
344                 close(netsocket);
345         }
346         return ns;
347 }
348
349 static void ast_netsock_destroy(struct ast_netsock *netsock)
350 {
351         ast_io_remove(netsock->ioc, netsock->ioref);
352         close(netsock->sockfd);
353         free(netsock);
354 }
355
356 int ast_netsock_init(struct ast_netsock_list *list)
357 {
358         memset(list, 0, sizeof(struct ast_netsock_list));
359         ASTOBJ_CONTAINER_INIT(list);
360         return 0;
361 }
362
363 int ast_netsock_release(struct ast_netsock_list *list)
364 {
365         ASTOBJ_CONTAINER_DESTROYALL(list, ast_netsock_destroy);
366         ASTOBJ_CONTAINER_DESTROY(list);
367         return 0;
368 }
369
370 const struct sockaddr_in *ast_netsock_boundaddr(struct ast_netsock *ns)
371 {
372         return &(ns->bindaddr);
373 }
374
375 void *ast_netsock_data(struct ast_netsock *ns)
376 {
377         return ns->data;
378 }
379
380 struct ast_netsock *ast_netsock_bind(struct ast_netsock_list *list, struct io_context *ioc, const char *bindinfo, int defaultport, int tos, ast_io_cb callback, void *data)
381 {
382         struct sockaddr_in sin;
383         char *tmp;
384         char *port;
385         int portno;
386         memset(&sin, 0, sizeof(sin));
387         sin.sin_family = AF_INET;
388         sin.sin_port = htons(defaultport);
389         tmp = ast_strdupa(bindinfo);
390         if (tmp) {
391                 port = strchr(tmp, ':');
392                 if (port) {
393                         *port = '\0';
394                         port++;
395                         if ((portno = atoi(port)) > 0) 
396                                 sin.sin_port = htons(portno);
397                 }
398                 inet_aton(tmp, &sin.sin_addr);
399                 return ast_netsock_bindaddr(list, ioc, &sin, tos, callback, data);
400         } else
401                 ast_log(LOG_WARNING, "Out of memory!\n");
402         return NULL;
403 }
404
405 int ast_find_ourip(struct in_addr *ourip, struct sockaddr_in bindaddr)
406 {
407         char ourhost[256];
408         struct ast_hostent ahp;
409         struct hostent *hp;
410         struct in_addr saddr;
411
412         /* just use the bind address if it is nonzero */
413         if (ntohl(bindaddr.sin_addr.s_addr)) {
414                 memcpy(ourip, &bindaddr.sin_addr, sizeof(*ourip));
415                 return 0;
416         }
417         /* try to use our hostname */
418         if (gethostname(ourhost, sizeof(ourhost))) {
419                 ast_log(LOG_WARNING, "Unable to get hostname\n");
420         } else {
421                 hp = ast_gethostbyname(ourhost, &ahp);
422                 if (hp) {
423                         memcpy(ourip, hp->h_addr, sizeof(*ourip));
424                         return 0;
425                 }
426         }
427         /* A.ROOT-SERVERS.NET. */
428         if (inet_aton("198.41.0.4", &saddr) && !ast_ouraddrfor(&saddr, ourip))
429                 return 0;
430         return -1;
431 }
432