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