/src/rtpproxy/src/rtpp_network.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2004-2006 Maxim Sobolev <sobomax@FreeBSD.org> |
3 | | * Copyright (c) 2006-2009 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 <arpa/inet.h> |
33 | | #include <assert.h> |
34 | | #include <ctype.h> |
35 | | #include <netdb.h> |
36 | | #include <stdio.h> |
37 | | #include <stdlib.h> |
38 | | #include <string.h> |
39 | | #include <unistd.h> |
40 | | |
41 | | #include "config_pp.h" |
42 | | |
43 | | #if !defined(NO_ERR_H) |
44 | | #include <err.h> |
45 | | #endif |
46 | | |
47 | | #include "rtpp_network.h" |
48 | | |
49 | | int |
50 | | ishostseq(const struct sockaddr *ia1, const struct sockaddr *ia2) |
51 | 58.8M | { |
52 | | |
53 | 58.8M | if (ia1->sa_family != ia2->sa_family) |
54 | 23.5M | return 0; |
55 | | |
56 | 35.3M | switch (ia1->sa_family) { |
57 | 35.2M | case AF_INET: |
58 | 35.2M | return (satosin(ia1)->sin_addr.s_addr == |
59 | 35.2M | satosin(ia2)->sin_addr.s_addr); |
60 | | |
61 | 34.5k | case AF_INET6: |
62 | 34.5k | return (memcmp(&satosin6(ia1)->sin6_addr.s6_addr[0], |
63 | 34.5k | &satosin6(ia2)->sin6_addr.s6_addr[0], |
64 | 34.5k | sizeof(struct in6_addr)) == 0); |
65 | | |
66 | 0 | default: |
67 | 0 | break; |
68 | 35.3M | } |
69 | | /* Can't happen */ |
70 | 0 | abort(); |
71 | 35.3M | } |
72 | | |
73 | | int |
74 | | ishostnull(const struct sockaddr *ia) |
75 | 204 | { |
76 | 204 | struct in6_addr *ap; |
77 | | |
78 | 204 | switch (ia->sa_family) { |
79 | 31 | case AF_INET: |
80 | 31 | return (satosin(ia)->sin_addr.s_addr == INADDR_ANY); |
81 | | |
82 | 173 | case AF_INET6: |
83 | 173 | ap = &satosin6(ia)->sin6_addr; |
84 | 173 | return ((*(const uint32_t *)(const void *)(&ap->s6_addr[0]) == 0) && |
85 | 173 | (*(const uint32_t *)(const void *)(&ap->s6_addr[4]) == 0) && |
86 | 173 | (*(const uint32_t *)(const void *)(&ap->s6_addr[8]) == 0) && |
87 | 173 | (*(const uint32_t *)(const void *)(&ap->s6_addr[12]) == 0)); |
88 | | |
89 | 0 | default: |
90 | 0 | break; |
91 | 204 | } |
92 | | |
93 | 0 | abort(); |
94 | 204 | } |
95 | | |
96 | | uint16_t |
97 | | getport(const struct sockaddr *ia) |
98 | 0 | { |
99 | |
|
100 | 0 | return (ntohs(getnport(ia))); |
101 | 0 | } |
102 | | |
103 | | uint16_t |
104 | | getnport(const struct sockaddr *ia) |
105 | 0 | { |
106 | |
|
107 | 0 | switch (ia->sa_family) { |
108 | 0 | case AF_INET: |
109 | 0 | return (satosin(ia)->sin_port); |
110 | | |
111 | 0 | case AF_INET6: |
112 | 0 | return (satosin6(ia)->sin6_port); |
113 | | |
114 | 0 | default: |
115 | 0 | break; |
116 | 0 | } |
117 | | /* Can't happen */ |
118 | 0 | abort(); |
119 | 0 | } |
120 | | |
121 | | int |
122 | | isaddrseq(const struct sockaddr *ia1, const struct sockaddr *ia2) |
123 | 0 | { |
124 | |
|
125 | 0 | if (ishostseq(ia1, ia2) == 0) |
126 | 0 | return (0); |
127 | 0 | return (getport(ia1) == getport(ia2)); |
128 | 0 | } |
129 | | |
130 | | void |
131 | | setport(struct sockaddr *ia, int portnum) |
132 | 0 | { |
133 | |
|
134 | 0 | assert(IS_VALID_PORT(portnum)); |
135 | | |
136 | 0 | switch (ia->sa_family) { |
137 | 0 | case AF_INET: |
138 | 0 | satosin(ia)->sin_port = htons(portnum); |
139 | 0 | return; |
140 | | |
141 | 0 | case AF_INET6: |
142 | 0 | satosin6(ia)->sin6_port = htons(portnum); |
143 | 0 | return; |
144 | | |
145 | 0 | default: |
146 | 0 | break; |
147 | 0 | } |
148 | | /* Can't happen */ |
149 | 0 | abort(); |
150 | 0 | } |
151 | | |
152 | | void |
153 | | setanyport(struct sockaddr *ia) |
154 | 0 | { |
155 | |
|
156 | 0 | switch (ia->sa_family) { |
157 | 0 | case AF_INET: |
158 | 0 | satosin(ia)->sin_port = 0; |
159 | 0 | return; |
160 | | |
161 | 0 | case AF_INET6: |
162 | 0 | satosin6(ia)->sin6_port = 0; |
163 | 0 | return; |
164 | | |
165 | 0 | default: |
166 | 0 | break; |
167 | 0 | } |
168 | | /* Can't happen */ |
169 | 0 | abort(); |
170 | 0 | } |
171 | | |
172 | | char * |
173 | | addr2char_r(const struct sockaddr *ia, char *buf, int size) |
174 | 0 | { |
175 | 0 | void *addr; |
176 | |
|
177 | 0 | switch (ia->sa_family) { |
178 | 0 | case AF_INET: |
179 | 0 | addr = &(satosin(ia)->sin_addr); |
180 | 0 | break; |
181 | | |
182 | 0 | case AF_INET6: |
183 | 0 | addr = &(satosin6(ia)->sin6_addr); |
184 | 0 | break; |
185 | | |
186 | 0 | default: |
187 | 0 | abort(); |
188 | 0 | } |
189 | | |
190 | 0 | return (char *)((void *)inet_ntop(ia->sa_family, addr, buf, size)); |
191 | 0 | } |
192 | | |
193 | | char * |
194 | | addrport2char_r(const struct sockaddr *ia, char *buf, int size, char portsep) |
195 | 0 | { |
196 | 0 | char abuf[MAX_ADDR_STRLEN]; |
197 | 0 | const char *bs, *es; |
198 | |
|
199 | 0 | switch (ia->sa_family) { |
200 | 0 | case AF_INET: |
201 | 0 | bs = es = ""; |
202 | 0 | break; |
203 | | |
204 | 0 | case AF_INET6: |
205 | 0 | bs = "["; |
206 | 0 | es = "]"; |
207 | 0 | break; |
208 | | |
209 | 0 | default: |
210 | 0 | abort(); |
211 | 0 | } |
212 | | |
213 | 0 | if (addr2char_r(ia, abuf, MAX_ADDR_STRLEN) == NULL) |
214 | 0 | return (NULL); |
215 | 0 | snprintf(buf, size, "%s%s%s%c%u", bs, abuf, es, portsep, getport(ia)); |
216 | 0 | return (buf); |
217 | 0 | } |
218 | | |
219 | | int |
220 | | resolve(struct sockaddr *ia, int pf, const char *host, |
221 | | const char *servname, int flags) |
222 | 262k | { |
223 | 262k | int n; |
224 | 262k | struct addrinfo hints, *res; |
225 | | |
226 | 262k | memset(&hints, 0, sizeof(hints)); |
227 | 262k | hints.ai_flags = flags; /* We create listening sockets */ |
228 | 262k | hints.ai_family = pf; /* Protocol family */ |
229 | 262k | hints.ai_socktype = SOCK_DGRAM; /* UDP */ |
230 | | |
231 | 262k | n = getaddrinfo(host, servname, &hints, &res); |
232 | 262k | if (n == 0) { |
233 | | /* Use the first socket address returned */ |
234 | 262k | memcpy(ia, res->ai_addr, res->ai_addrlen); |
235 | 262k | freeaddrinfo(res); |
236 | 262k | } |
237 | | |
238 | 262k | return n; |
239 | 262k | } |
240 | | |
241 | | #if !defined(BYTE_ORDER) |
242 | | # error "BYTE_ORDER needs to be defined" |
243 | | #endif |
244 | | |
245 | | /* |
246 | | * Checksum routine for Internet Protocol family headers. |
247 | | */ |
248 | | uint16_t |
249 | | rtpp_in_cksum(void *p, int len) |
250 | 0 | { |
251 | 0 | int sum = 0, oddbyte = 0, v = 0; |
252 | 0 | u_char *cp = p; |
253 | | |
254 | | /* we assume < 2^16 bytes being summed */ |
255 | 0 | while (len > 0) { |
256 | 0 | if (oddbyte) { |
257 | 0 | sum += v + *cp++; |
258 | 0 | len--; |
259 | 0 | } |
260 | 0 | if (((long)cp & 1) == 0) { |
261 | 0 | while ((len -= 2) >= 0) { |
262 | 0 | sum += *(u_short *)cp; |
263 | 0 | cp += 2; |
264 | 0 | } |
265 | 0 | } else { |
266 | 0 | while ((len -= 2) >= 0) { |
267 | | #if BYTE_ORDER == BIG_ENDIAN |
268 | | sum += *cp++ << 8; |
269 | | sum += *cp++; |
270 | | #else |
271 | 0 | sum += *cp++; |
272 | 0 | sum += *cp++ << 8; |
273 | 0 | #endif |
274 | 0 | } |
275 | 0 | } |
276 | 0 | if ((oddbyte = len & 1) != 0) { |
277 | | #if BYTE_ORDER == BIG_ENDIAN |
278 | | v = *cp << 8; |
279 | | #else |
280 | 0 | v = *cp; |
281 | 0 | #endif |
282 | 0 | } |
283 | 0 | } |
284 | 0 | if (oddbyte) |
285 | 0 | sum += v; |
286 | 0 | sum = (sum >> 16) + (sum & 0xffff); /* add in accumulated carries */ |
287 | 0 | sum += sum >> 16; /* add potential last carry */ |
288 | 0 | return (0xffff & ~sum); |
289 | 0 | } |
290 | | |
291 | | int |
292 | | local4remote(const struct sockaddr *ra, struct sockaddr_storage *la) |
293 | 10 | { |
294 | 10 | int s, r; |
295 | 10 | socklen_t llen; |
296 | | |
297 | 10 | s = socket(ra->sa_family, SOCK_DGRAM, 0); |
298 | 10 | if (s == -1) { |
299 | 0 | return (-1); |
300 | 0 | } |
301 | 10 | if (connect(s, ra, SA_LEN(ra)) == -1) { |
302 | 0 | close(s); |
303 | 0 | return (-1); |
304 | 0 | } |
305 | 10 | llen = sizeof(*la); |
306 | 10 | r = getsockname(s, sstosa(la), &llen); |
307 | 10 | close(s); |
308 | 10 | return (r); |
309 | 10 | } |
310 | | |
311 | | int |
312 | | extractaddr(const char *str, const char **begin, const char **end, int *pf) |
313 | 262k | { |
314 | 262k | const char *t; |
315 | 262k | int tpf; |
316 | | |
317 | 262k | if (*str != '[') { |
318 | 261k | tpf = AF_INET; |
319 | 536k | for (t = str; *str != '\0'; str++) { |
320 | 536k | if (!isdigit(*str) && *str != '.') |
321 | 261k | break; |
322 | 536k | } |
323 | 261k | } else { |
324 | 494 | tpf = AF_INET6; |
325 | 494 | str++; |
326 | 3.57k | for (t = str; *str != '\0'; str++) { |
327 | 3.57k | if (!isxdigit(*str) && *str != ':') |
328 | 488 | break; |
329 | 3.57k | } |
330 | 494 | if (*str != ']') |
331 | 25 | return (-1); |
332 | 494 | } |
333 | 262k | if (t == str) |
334 | 160 | return (-1); |
335 | 262k | if (tpf == AF_INET6) |
336 | 462 | *end = (char *)(str + 1); |
337 | 261k | else |
338 | 261k | *end = (char *)str; |
339 | 262k | *pf = tpf; |
340 | 262k | *begin = (char *)t; |
341 | 262k | return(str - t); |
342 | 262k | } |
343 | | |
344 | | int |
345 | | setbindhost(struct sockaddr *ia, int pf, const char *bindhost, |
346 | | const char *servname) |
347 | 0 | { |
348 | 0 | int n; |
349 | | |
350 | | /* |
351 | | * If user specified * then change it to NULL, |
352 | | * that will make getaddrinfo to return addr_any socket |
353 | | */ |
354 | 0 | if (bindhost && (strcmp(bindhost, "*") == 0)) |
355 | 0 | bindhost = NULL; |
356 | |
|
357 | 0 | if ((n = resolve(ia, pf, bindhost, servname, AI_PASSIVE)) != 0) { |
358 | 0 | warnx("setbindhost: %s for %s %s", gai_strerror(n), bindhost, servname); |
359 | 0 | return -1; |
360 | 0 | } |
361 | 0 | return 0; |
362 | 0 | } |