/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_codeptr.h" |
49 | | #include "rtpp_refcnt.h" |
50 | | #include "rtpp_str.h" |
51 | | #include "rtpp_bindaddr.h" |
52 | | #include "rtpp_bindaddrs.h" |
53 | | |
54 | | struct bindaddr_list { |
55 | | struct rtpp_bindaddr bindaddr; |
56 | | struct bindaddr_list *next; |
57 | | }; |
58 | | |
59 | | struct rtpp_bindaddrs_pvt { |
60 | | struct rtpp_bindaddrs pub; |
61 | | struct bindaddr_list *bindaddr_list; |
62 | | pthread_mutex_t bindaddr_lock; |
63 | | }; |
64 | | |
65 | | static void rtpp_bindaddrs_dtor(struct rtpp_bindaddrs_pvt *); |
66 | | |
67 | | static const struct rtpp_bindaddr * |
68 | | addr2bindaddr_i(struct rtpp_bindaddrs *pub, const struct sockaddr *ia, |
69 | | const char **ep, const struct rtpp_bindaddr_params *params) |
70 | 0 | { |
71 | 0 | struct bindaddr_list *bl; |
72 | 0 | struct rtpp_bindaddrs_pvt *cf; |
73 | 0 | struct sockaddr_storage *ap; |
74 | |
|
75 | 0 | PUB2PVT(pub, cf); |
76 | 0 | pthread_mutex_lock(&cf->bindaddr_lock); |
77 | 0 | for (bl = cf->bindaddr_list; bl != NULL; bl = bl->next) { |
78 | 0 | const struct rtpp_bindaddr *ba = &bl->bindaddr; |
79 | 0 | if (ishostseq(ba->addr, ia) != 0) { |
80 | 0 | const rtpp_str_const_t *bll = &ba->params.label; |
81 | 0 | if (params != NULL && !rtpp_str_match(¶ms->label, bll)) |
82 | 0 | continue; |
83 | 0 | pthread_mutex_unlock(&cf->bindaddr_lock); |
84 | 0 | return (ba); |
85 | 0 | } |
86 | 0 | } |
87 | 0 | bl = rtpp_zmalloc(sizeof(*bl) + sizeof(struct sockaddr_storage)); |
88 | 0 | if (bl == NULL) { |
89 | 0 | pthread_mutex_unlock(&cf->bindaddr_lock); |
90 | 0 | *ep = strerror(errno); |
91 | 0 | return (NULL); |
92 | 0 | } |
93 | 0 | ap = (struct sockaddr_storage *)((char *)bl + sizeof(*bl)); |
94 | 0 | memcpy(ap, ia, SA_LEN(ia)); |
95 | 0 | bl->bindaddr.addr = sstosa(ap); |
96 | 0 | if (params != NULL) { |
97 | 0 | bl->bindaddr.params = *params; |
98 | 0 | } |
99 | 0 | bl->next = cf->bindaddr_list; |
100 | 0 | cf->bindaddr_list = bl; |
101 | 0 | pthread_mutex_unlock(&cf->bindaddr_lock); |
102 | 0 | return (&bl->bindaddr); |
103 | 0 | } |
104 | | |
105 | | static const struct rtpp_bindaddr * |
106 | | addr2bindaddr(struct rtpp_bindaddrs *pub, const struct sockaddr *ia, |
107 | | const char **ep) |
108 | 0 | { |
109 | |
|
110 | 0 | return addr2bindaddr_i(pub, ia, ep, NULL); |
111 | 0 | } |
112 | | |
113 | | static const struct rtpp_bindaddr * |
114 | | label2bindaddr(struct rtpp_bindaddrs *pub, const rtpp_str_const_t *label) |
115 | 0 | { |
116 | 0 | struct bindaddr_list *bl; |
117 | 0 | struct rtpp_bindaddrs_pvt *cf; |
118 | |
|
119 | 0 | PUB2PVT(pub, cf); |
120 | 0 | pthread_mutex_lock(&cf->bindaddr_lock); |
121 | 0 | for (bl = cf->bindaddr_list; bl != NULL; bl = bl->next) { |
122 | 0 | const rtpp_str_const_t *blabel = &bl->bindaddr.params.label; |
123 | 0 | if (blabel->s != NULL && rtpp_str_match(blabel, label)) |
124 | 0 | break; |
125 | 0 | } |
126 | 0 | pthread_mutex_unlock(&cf->bindaddr_lock); |
127 | 0 | return (bl == NULL ? NULL : &bl->bindaddr); |
128 | 0 | } |
129 | | |
130 | | static const struct rtpp_bindaddr * |
131 | | host2bindaddr(struct rtpp_bindaddrs *pub, const char *host, int pf, |
132 | | int ai_flags, const char **ep, const struct rtpp_bindaddr_params *params) |
133 | 0 | { |
134 | 0 | int n; |
135 | 0 | struct sockaddr_storage ia; |
136 | 0 | const struct rtpp_bindaddr *rval; |
137 | |
|
138 | 0 | if (params != NULL && params->label.s != NULL && label2bindaddr(pub, ¶ms->label) != NULL) { |
139 | 0 | *ep = "duplicate label"; |
140 | 0 | return (NULL); |
141 | 0 | } |
142 | | |
143 | | /* |
144 | | * If user specified * then change it to NULL, |
145 | | * that will make getaddrinfo to return addr_any socket |
146 | | */ |
147 | 0 | if (host != NULL && is_wildcard(host, pf)) |
148 | 0 | host = NULL; |
149 | |
|
150 | 0 | if (host != NULL) { |
151 | 0 | ai_flags |= is_numhost(host, pf) ? AI_NUMERICHOST : 0; |
152 | 0 | } else { |
153 | 0 | ai_flags &= ~AI_ADDRCONFIG; |
154 | 0 | } |
155 | |
|
156 | 0 | if ((n = resolve(sstosa(&ia), pf, host, SERVICE, ai_flags)) != 0) { |
157 | 0 | *ep = gai_strerror(n); |
158 | 0 | return (NULL); |
159 | 0 | } |
160 | 0 | rval = addr2bindaddr_i(pub, sstosa(&ia), ep, params); |
161 | 0 | return (rval); |
162 | 0 | } |
163 | | |
164 | | static const struct rtpp_bindaddr * |
165 | | bindaddr4af(struct rtpp_bindaddrs *pub, int af) |
166 | 0 | { |
167 | 0 | struct bindaddr_list *bl; |
168 | 0 | struct rtpp_bindaddrs_pvt *cf; |
169 | |
|
170 | 0 | PUB2PVT(pub, cf); |
171 | 0 | pthread_mutex_lock(&cf->bindaddr_lock); |
172 | 0 | for (bl = cf->bindaddr_list; bl != NULL; bl = bl->next) { |
173 | 0 | if (bl->bindaddr.addr->sa_family == af) { |
174 | 0 | pthread_mutex_unlock(&cf->bindaddr_lock); |
175 | 0 | return (&bl->bindaddr); |
176 | 0 | } |
177 | 0 | } |
178 | 0 | pthread_mutex_unlock(&cf->bindaddr_lock); |
179 | 0 | return (NULL); |
180 | 0 | } |
181 | | |
182 | | static void |
183 | | rtpp_bindaddrs_dtor(struct rtpp_bindaddrs_pvt *cf) |
184 | 0 | { |
185 | 0 | struct bindaddr_list *bl, *bl_next; |
186 | |
|
187 | 0 | for (bl = cf->bindaddr_list; bl != NULL; bl = bl_next) { |
188 | 0 | bl_next = bl->next; |
189 | 0 | free(bl); |
190 | 0 | } |
191 | 0 | pthread_mutex_destroy(&cf->bindaddr_lock); |
192 | 0 | } |
193 | | |
194 | | static const struct rtpp_bindaddr * |
195 | | rtpp_bindaddrs_local4remote(struct rtpp_bindaddrs *pub, const struct rtpp_cfg *cfsp, |
196 | | struct rtpp_log *log, int pf, const char *host, const char *port) |
197 | 0 | { |
198 | 0 | struct sockaddr_storage local_addr; |
199 | 0 | const struct rtpp_bindaddr *rval; |
200 | 0 | const char *errmsg; |
201 | |
|
202 | 0 | int ai_flags = cfsp->no_resolve ? AI_NUMERICHOST : 0; |
203 | 0 | int n = resolve(sstosa(&local_addr), pf, host, port, ai_flags); |
204 | 0 | if (n != 0) { |
205 | 0 | RTPP_LOG(log, RTPP_LOG_ERR, "invalid remote address: %s: %s", host, |
206 | 0 | gai_strerror(n)); |
207 | 0 | return (NULL); |
208 | 0 | } |
209 | 0 | if (local4remote(sstosa(&local_addr), &local_addr) == -1) { |
210 | 0 | RTPP_LOG(log, RTPP_LOG_ERR, "can't find local address for remote address: %s", |
211 | 0 | host); |
212 | 0 | return (NULL); |
213 | 0 | } |
214 | 0 | rval = addr2bindaddr(pub, sstosa(&local_addr), &errmsg); |
215 | 0 | if (rval == NULL) { |
216 | 0 | RTPP_LOG(log, RTPP_LOG_ERR, "invalid local address: %s", errmsg); |
217 | 0 | return (NULL); |
218 | 0 | } |
219 | 0 | return (rval); |
220 | 0 | } |
221 | | |
222 | | DEFINE_SMETHODS(rtpp_bindaddrs, |
223 | | .addr2 = &addr2bindaddr, |
224 | | .label2 = &label2bindaddr, |
225 | | .host2 = &host2bindaddr, |
226 | | .foraf = &bindaddr4af, |
227 | | .local4remote = &rtpp_bindaddrs_local4remote, |
228 | | ); |
229 | | |
230 | | struct rtpp_bindaddrs * |
231 | | rtpp_bindaddrs_ctor(void) |
232 | 0 | { |
233 | 0 | struct rtpp_bindaddrs_pvt *cf; |
234 | |
|
235 | 0 | cf = rtpp_rzmalloc(sizeof(*cf), PVT_RCOFFS(cf)); |
236 | 0 | if (cf == NULL) |
237 | 0 | goto e0; |
238 | 0 | if (pthread_mutex_init(&cf->bindaddr_lock, NULL) != 0) |
239 | 0 | goto e1; |
240 | 0 | PUBINST_FININIT(&cf->pub, cf, rtpp_bindaddrs_dtor); |
241 | 0 | return (&(cf->pub)); |
242 | 0 | e1: |
243 | 0 | RTPP_OBJ_DECREF(&(cf->pub)); |
244 | 0 | e0: |
245 | | return (NULL); |
246 | 0 | } |