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