/src/rtpproxy/src/rtpp_bindaddrs.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2004-2006 Maxim Sobolev <sobomax@FreeBSD.org> |
3 | | * Copyright (c) 2006-2016 Sippy Software, Inc., http://www.sippysoft.com |
4 | | * All rights reserved. |
5 | | * |
6 | | * Redistribution and use in source and binary forms, with or without |
7 | | * modification, are permitted provided that the following conditions |
8 | | * are met: |
9 | | * 1. Redistributions of source code must retain the above copyright |
10 | | * notice, this list of conditions and the following disclaimer. |
11 | | * 2. Redistributions in binary form must reproduce the above copyright |
12 | | * notice, this list of conditions and the following disclaimer in the |
13 | | * documentation and/or other materials provided with the distribution. |
14 | | * |
15 | | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
16 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
19 | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
21 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
22 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
23 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 | | * SUCH DAMAGE. |
26 | | * |
27 | | */ |
28 | | |
29 | | #include <sys/types.h> |
30 | | #include <sys/socket.h> |
31 | | #include <netinet/in.h> |
32 | | #include <errno.h> |
33 | | #include <netdb.h> |
34 | | #include <pthread.h> |
35 | | #include <stddef.h> |
36 | | #include <stdlib.h> |
37 | | #include <string.h> |
38 | | |
39 | | #include "config.h" |
40 | | |
41 | | #include "rtpp_types.h" |
42 | | #include "rtpp_defines.h" |
43 | | #include "rtpp_cfg.h" |
44 | | #include "rtpp_log.h" |
45 | | #include "rtpp_log_obj.h" |
46 | | #include "rtpp_network.h" |
47 | | #include "rtpp_mallocs.h" |
48 | | #include "rtpp_bindaddrs.h" |
49 | | |
50 | | struct bindaddr_list { |
51 | | struct sockaddr_storage *bindaddr; |
52 | | struct bindaddr_list *next; |
53 | | }; |
54 | | |
55 | | struct rtpp_bindaddrs_pvt { |
56 | | struct rtpp_bindaddrs pub; |
57 | | struct bindaddr_list *bindaddr_list; |
58 | | pthread_mutex_t bindaddr_lock; |
59 | | }; |
60 | | |
61 | | static const struct sockaddr * |
62 | | addr2bindaddr(struct rtpp_bindaddrs *pub, const struct sockaddr *ia, const char **ep) |
63 | 1.41k | { |
64 | 1.41k | struct bindaddr_list *bl; |
65 | 1.41k | struct rtpp_bindaddrs_pvt *cf; |
66 | | |
67 | 1.41k | PUB2PVT(pub, cf); |
68 | 1.41k | pthread_mutex_lock(&cf->bindaddr_lock); |
69 | 152k | for (bl = cf->bindaddr_list; bl != NULL; bl = bl->next) { |
70 | 152k | if (ishostseq(sstosa(bl->bindaddr), ia) != 0) { |
71 | 1.24k | pthread_mutex_unlock(&cf->bindaddr_lock); |
72 | 1.24k | return (sstosa(bl->bindaddr)); |
73 | 1.24k | } |
74 | 152k | } |
75 | 173 | bl = malloc(sizeof(*bl) + sizeof(*bl->bindaddr)); |
76 | 173 | if (bl == NULL) { |
77 | 0 | pthread_mutex_unlock(&cf->bindaddr_lock); |
78 | 0 | *ep = strerror(errno); |
79 | 0 | return (NULL); |
80 | 0 | } |
81 | 173 | bl->bindaddr = (struct sockaddr_storage *)((char *)bl + sizeof(*bl)); |
82 | 173 | memcpy(bl->bindaddr, ia, SA_LEN(ia)); |
83 | 173 | bl->next = cf->bindaddr_list; |
84 | 173 | cf->bindaddr_list = bl; |
85 | 173 | pthread_mutex_unlock(&cf->bindaddr_lock); |
86 | 173 | return (sstosa(bl->bindaddr)); |
87 | 173 | } |
88 | | |
89 | | static const struct sockaddr * |
90 | | host2bindaddr(struct rtpp_bindaddrs *pub, const char *host, int pf, |
91 | | int ai_flags, const char **ep) |
92 | 1.25k | { |
93 | 1.25k | int n; |
94 | 1.25k | struct sockaddr_storage ia; |
95 | 1.25k | const struct sockaddr *rval; |
96 | | |
97 | | /* |
98 | | * If user specified * then change it to NULL, |
99 | | * that will make getaddrinfo to return addr_any socket |
100 | | */ |
101 | 1.25k | if (host != NULL && is_wildcard(host, pf)) |
102 | 404 | host = NULL; |
103 | | |
104 | 1.25k | if (host != NULL) { |
105 | 848 | ai_flags |= is_numhost(host, pf) ? AI_NUMERICHOST : 0; |
106 | 848 | } else { |
107 | 404 | ai_flags &= ~AI_ADDRCONFIG; |
108 | 404 | } |
109 | | |
110 | 1.25k | if ((n = resolve(sstosa(&ia), pf, host, SERVICE, ai_flags)) != 0) { |
111 | 39 | *ep = gai_strerror(n); |
112 | 39 | return (NULL); |
113 | 39 | } |
114 | 1.21k | rval = addr2bindaddr(pub, sstosa(&ia), ep); |
115 | 1.21k | return (rval); |
116 | 1.25k | } |
117 | | |
118 | | static const struct sockaddr * |
119 | | bindaddr4af(struct rtpp_bindaddrs *pub, int af) |
120 | 2.09k | { |
121 | 2.09k | struct bindaddr_list *bl; |
122 | 2.09k | struct rtpp_bindaddrs_pvt *cf; |
123 | | |
124 | 2.09k | PUB2PVT(pub, cf); |
125 | 2.09k | pthread_mutex_lock(&cf->bindaddr_lock); |
126 | 34.3k | for (bl = cf->bindaddr_list; bl != NULL; bl = bl->next) { |
127 | 34.3k | if (sstosa(bl->bindaddr)->sa_family == af) { |
128 | 2.05k | pthread_mutex_unlock(&cf->bindaddr_lock); |
129 | 2.05k | return (sstosa(bl->bindaddr)); |
130 | 2.05k | } |
131 | 34.3k | } |
132 | 36 | pthread_mutex_unlock(&cf->bindaddr_lock); |
133 | 36 | return (NULL); |
134 | 2.09k | } |
135 | | |
136 | | static void |
137 | | rtpp_bindaddrs_dtor(struct rtpp_bindaddrs *pub) |
138 | 4 | { |
139 | 4 | struct rtpp_bindaddrs_pvt *cf; |
140 | 4 | struct bindaddr_list *bl, *bl_next; |
141 | | |
142 | 4 | PUB2PVT(pub, cf); |
143 | 177 | for (bl = cf->bindaddr_list; bl != NULL; bl = bl_next) { |
144 | 173 | bl_next = bl->next; |
145 | 173 | free(bl); |
146 | 173 | } |
147 | 4 | free(cf); |
148 | 4 | } |
149 | | |
150 | | static const struct sockaddr * |
151 | | rtpp_bindaddrs_local4remote(struct rtpp_bindaddrs *pub, const struct rtpp_cfg *cfsp, |
152 | | struct rtpp_log *log, int pf, const char *host, const char *port) |
153 | 683 | { |
154 | 683 | struct sockaddr_storage local_addr; |
155 | 683 | const struct sockaddr *rval; |
156 | 683 | const char *errmsg; |
157 | | |
158 | 683 | int ai_flags = cfsp->no_resolve ? AI_NUMERICHOST : 0; |
159 | 683 | int n = resolve(sstosa(&local_addr), pf, host, port, ai_flags); |
160 | 683 | if (n != 0) { |
161 | 479 | RTPP_LOG(log, RTPP_LOG_ERR, "invalid remote address: %s: %s", host, |
162 | 479 | gai_strerror(n)); |
163 | 479 | return (NULL); |
164 | 479 | } |
165 | 204 | if (local4remote(sstosa(&local_addr), &local_addr) == -1) { |
166 | 1 | RTPP_LOG(log, RTPP_LOG_ERR, "can't find local address for remote address: %s", |
167 | 1 | host); |
168 | 1 | return (NULL); |
169 | 1 | } |
170 | 203 | rval = addr2bindaddr(pub, sstosa(&local_addr), &errmsg); |
171 | 203 | if (rval == NULL) { |
172 | 0 | RTPP_LOG(log, RTPP_LOG_ERR, "invalid local address: %s", errmsg); |
173 | 0 | return (NULL); |
174 | 0 | } |
175 | 203 | return (rval); |
176 | 203 | } |
177 | | |
178 | | struct rtpp_bindaddrs * |
179 | | rtpp_bindaddrs_ctor(void) |
180 | 4 | { |
181 | 4 | struct rtpp_bindaddrs_pvt *cf; |
182 | | |
183 | 4 | cf = rtpp_zmalloc(sizeof(*cf)); |
184 | 4 | if (cf == NULL) |
185 | 0 | goto e0; |
186 | 4 | if (pthread_mutex_init(&cf->bindaddr_lock, NULL) != 0) |
187 | 0 | goto e1; |
188 | 4 | cf->pub.addr2 = addr2bindaddr; |
189 | 4 | cf->pub.host2 = host2bindaddr; |
190 | 4 | cf->pub.foraf = bindaddr4af; |
191 | 4 | cf->pub.dtor = rtpp_bindaddrs_dtor; |
192 | 4 | cf->pub.local4remote = rtpp_bindaddrs_local4remote; |
193 | 4 | return (&(cf->pub)); |
194 | 0 | e1: |
195 | 0 | free(cf); |
196 | 0 | e0: |
197 | | return (NULL); |
198 | 0 | } |