2 * Asterisk -- A telephony toolkit for Linux.
4 * Various sorts of access control
6 * Copyright (C) 1999, Mark Spencer
8 * Mark Spencer <markster@linux-support.net>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
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>
32 #include <netinet/in_systm.h>
33 #include <netinet/ip.h>
34 #include <sys/ioctl.h>
35 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
37 #include <net/route.h>
39 AST_MUTEX_DEFINE_STATIC(routeseq_lock);
43 #include <sys/sockio.h>
47 ASTOBJ_COMPONENTS(struct ast_netsock);
48 struct sockaddr_in bindaddr;
51 struct io_context *ioc;
57 /* Host access rule */
58 struct in_addr netaddr;
59 struct in_addr netmask;
64 /* Default IP - if not otherwise set, don't breathe garbage */
65 static struct in_addr __ourip = { 0x00000000 };
68 char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. "eth0", "ppp0", etc. */
69 struct sockaddr_in ifru_addr;
72 /* Free HA structure */
73 void ast_free_ha(struct ast_ha *ha)
83 /* Copy HA structure */
84 static void ast_copy_ha(struct ast_ha *from, struct ast_ha *to)
86 memcpy(&to->netaddr, &from->netaddr, sizeof(from->netaddr));
87 memcpy(&to->netmask, &from->netmask, sizeof(from->netmask));
88 to->sense = from->sense;
91 /* Create duplicate of ha structure */
92 static struct ast_ha *ast_duplicate_ha(struct ast_ha *original)
94 struct ast_ha *new_ha = malloc(sizeof(struct ast_ha));
96 /* Copy from original to new object */
97 ast_copy_ha(original, new_ha);
103 /* Create duplicate HA link list */
104 /* Used in chan_sip2 templates */
105 struct ast_ha *ast_duplicate_ha_list(struct ast_ha *original)
107 struct ast_ha *start=original;
108 struct ast_ha *ret = NULL;
109 struct ast_ha *link,*prev=NULL;
112 link = ast_duplicate_ha(start); /* Create copy of this object */
114 prev->next = link; /* Link previous to this object */
117 ret = link; /* Save starting point */
119 start = start->next; /* Go to next object */
120 prev = link; /* Save pointer to this object */
122 return (ret); /* Return start of list */
125 struct ast_ha *ast_append_ha(char *sense, char *stuff, struct ast_ha *path)
127 struct ast_ha *ha = malloc(sizeof(struct ast_ha));
128 char *nm="255.255.255.255";
130 struct ast_ha *prev = NULL;
140 strncpy(tmp, stuff, sizeof(tmp) - 1);
141 nm = strchr(tmp, '/');
143 nm = "255.255.255.255";
148 if (!strchr(nm, '.')) {
149 if ((sscanf(nm, "%i", &x) == 1) && (x >= 0) && (x <= 32)) {
155 ha->netmask.s_addr = htonl(y);
157 } else if (!inet_aton(nm, &ha->netmask)) {
158 ast_log(LOG_WARNING, "%s is not a valid netmask\n", nm);
162 if (!inet_aton(tmp, &ha->netaddr)) {
163 ast_log(LOG_WARNING, "%s is not a valid IP\n", tmp);
167 ha->netaddr.s_addr &= ha->netmask.s_addr;
168 if (!strncasecmp(sense, "p", 1)) {
169 ha->sense = AST_SENSE_ALLOW;
171 ha->sense = AST_SENSE_DENY;
179 ast_log(LOG_DEBUG, "%s/%s appended to acl for peer\n",stuff, nm);
183 int ast_apply_ha(struct ast_ha *ha, struct sockaddr_in *sin)
185 /* Start optimistic */
186 int res = AST_SENSE_ALLOW;
188 char iabuf[INET_ADDRSTRLEN];
189 char iabuf2[INET_ADDRSTRLEN];
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))
204 int ast_get_ip_or_srv(struct sockaddr_in *sin, const char *value, const char *service)
207 struct ast_hostent ahp;
210 int tportno = ntohs(sin->sin_port);
211 if (inet_aton(value, &sin->sin_addr))
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);
220 hp = ast_gethostbyname(value, &ahp);
222 memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
224 ast_log(LOG_WARNING, "Unable to lookup '%s'\n", value);
230 int ast_get_ip(struct sockaddr_in *sin, const char *value)
232 return ast_get_ip_or_srv(sin, value, NULL);
235 /* iface is the interface (e.g. eth0); address is the return value */
236 int ast_lookup_iface(char *iface, struct in_addr *address)
239 struct my_ifreq ifreq;
241 memset(&ifreq, 0, sizeof(ifreq));
242 strncpy(ifreq.ifrn_name,iface,sizeof(ifreq.ifrn_name) - 1);
244 mysock = socket(PF_INET,SOCK_DGRAM,IPPROTO_IP);
245 res = ioctl(mysock,SIOCGIFADDR,&ifreq);
249 ast_log(LOG_WARNING, "Unable to get IP of %s: %s\n", iface, strerror(errno));
250 memcpy((char *)address,(char *)&__ourip,sizeof(__ourip));
253 memcpy((char *)address,(char *)&ifreq.ifru_addr.sin_addr,sizeof(ifreq.ifru_addr.sin_addr));
258 int ast_ouraddrfor(struct in_addr *them, struct in_addr *us)
261 struct sockaddr_in sin;
264 s = socket(PF_INET, SOCK_DGRAM, 0);
266 ast_log(LOG_WARNING, "Cannot create socket\n");
269 sin.sin_family = AF_INET;
271 sin.sin_addr = *them;
272 if (connect(s, (struct sockaddr *)&sin, sizeof(sin))) {
273 ast_log(LOG_WARNING, "Cannot connect\n");
278 if (getsockname(s, (struct sockaddr *)&sin, &slen)) {
279 ast_log(LOG_WARNING, "Cannot get socket name\n");
288 int ast_netsock_sockfd(struct ast_netsock *ns)
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)
299 char iabuf[INET_ADDRSTRLEN];
301 struct ast_netsock *ns;
303 /* Make a UDP socket */
304 netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
307 ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
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));
315 if (option_verbose > 1)
316 ast_verbose(VERBOSE_PREFIX_2 "Using TOS bits %d\n", tos);
318 if (setsockopt(netsocket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)))
319 ast_log(LOG_WARNING, "Unable to set TOS to %d\n", tos);
321 ns = malloc(sizeof(struct ast_netsock));
323 /* Establish I/O callback for socket read */
324 ioref = ast_io_add(ioc, netsocket, callback, AST_IO_IN, ns);
326 ast_log(LOG_WARNING, "Out of memory!\n");
334 ns->sockfd = netsocket;
336 memcpy(&ns->bindaddr, bindaddr, sizeof(ns->bindaddr));
337 ASTOBJ_CONTAINER_LINK(list, ns);
339 ast_log(LOG_WARNING, "Out of memory!\n");
345 static void ast_netsock_destroy(struct ast_netsock *netsock)
347 ast_io_remove(netsock->ioc, netsock->ioref);
348 close(netsock->sockfd);
352 int ast_netsock_init(struct ast_netsock_list *list)
354 memset(list, 0, sizeof(struct ast_netsock_list));
355 ASTOBJ_CONTAINER_INIT(list);
359 int ast_netsock_release(struct ast_netsock_list *list)
361 ASTOBJ_CONTAINER_DESTROYALL(list, ast_netsock_destroy);
362 ASTOBJ_CONTAINER_DESTROY(list);
366 const struct sockaddr_in *ast_netsock_boundaddr(struct ast_netsock *ns)
368 return &(ns->bindaddr);
371 void *ast_netsock_data(struct ast_netsock *ns)
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)
378 struct sockaddr_in sin;
382 memset(&sin, 0, sizeof(sin));
383 sin.sin_family = AF_INET;
384 sin.sin_port = htons(defaultport);
385 tmp = ast_strdupa(bindinfo);
387 port = strchr(tmp, ':');
391 if ((portno = atoi(port)) > 0)
392 sin.sin_port = htons(portno);
394 inet_aton(tmp, &sin.sin_addr);
395 return ast_netsock_bindaddr(list, ioc, &sin, tos, callback, data);
397 ast_log(LOG_WARNING, "Out of memory!\n");
401 int ast_find_ourip(struct in_addr *ourip, struct sockaddr_in bindaddr)
404 struct ast_hostent ahp;
406 struct in_addr saddr;
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));
413 /* try to use our hostname */
414 if (gethostname(ourhost, sizeof(ourhost))) {
415 ast_log(LOG_WARNING, "Unable to get hostname\n");
417 hp = ast_gethostbyname(ourhost, &ahp);
419 memcpy(ourip, hp->h_addr, sizeof(*ourip));
423 /* A.ROOT-SERVERS.NET. */
424 if (inet_aton("198.41.0.4", &saddr) && !ast_ouraddrfor(&saddr, ourip))