/src/kamailio/src/core/socket_info.c
Line | Count | Source (jump to first uncovered line) |
1 | | |
2 | | /* |
3 | | * find & manage listen addresses |
4 | | * |
5 | | * Copyright (C) 2001-2003 FhG Fokus |
6 | | * |
7 | | * This file is part of Kamailio, a free SIP server. |
8 | | * |
9 | | * Kamailio is free software; you can redistribute it and/or modify |
10 | | * it under the terms of the GNU General Public License as published by |
11 | | * the Free Software Foundation; either version 2 of the License, or |
12 | | * (at your option) any later version |
13 | | * |
14 | | * Kamailio is distributed in the hope that it will be useful, |
15 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | | * GNU General Public License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU General Public License |
20 | | * along with this program; if not, write to the Free Software |
21 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
22 | | */ |
23 | | |
24 | | /*! |
25 | | * \file |
26 | | * \brief Kamailio core :: find & manage listen addresses |
27 | | * |
28 | | * This file contains code that initializes and handles Kamailio listen addresses |
29 | | * lists (struct socket_info). It is used mainly on startup. |
30 | | * \ingroup core |
31 | | * Module: \ref core |
32 | | */ |
33 | | |
34 | | #include <string.h> |
35 | | #include <errno.h> |
36 | | #include <unistd.h> |
37 | | #include <sys/types.h> |
38 | | #include <sys/socket.h> |
39 | | #include <sys/utsname.h> |
40 | | #include <stdio.h> |
41 | | |
42 | | #include <sys/ioctl.h> |
43 | | #include <net/if.h> |
44 | | #include <ifaddrs.h> |
45 | | #include <netdb.h> |
46 | | #ifdef HAVE_SYS_SOCKIO_H |
47 | | #include <sys/sockio.h> |
48 | | #endif |
49 | | |
50 | | #include "globals.h" |
51 | | #include "socket_info.h" |
52 | | #include "dprint.h" |
53 | | #include "mem/mem.h" |
54 | | #include "ut.h" |
55 | | #include "resolve.h" |
56 | | #include "name_alias.h" |
57 | | |
58 | | |
59 | | /* list manip. functions (internal use only) */ |
60 | | |
61 | | |
62 | | /* append */ |
63 | | #define sock_listadd(head, el) \ |
64 | 0 | do { \ |
65 | 0 | if(*(head) == 0) \ |
66 | 0 | *(head) = (el); \ |
67 | 0 | else { \ |
68 | 0 | for((el)->next = *(head); (el)->next->next; \ |
69 | 0 | (el)->next = (el)->next->next) \ |
70 | 0 | ; \ |
71 | 0 | (el)->next->next = (el); \ |
72 | 0 | (el)->prev = (el)->next; \ |
73 | 0 | (el)->next = 0; \ |
74 | 0 | } \ |
75 | 0 | } while(0) |
76 | | |
77 | | |
78 | | /* insert after "after" */ |
79 | | #define sock_listins(el, after) \ |
80 | 0 | do { \ |
81 | 0 | if((after)) { \ |
82 | 0 | (el)->next = (after)->next; \ |
83 | 0 | if((after)->next) \ |
84 | 0 | (after)->next->prev = (el); \ |
85 | 0 | (after)->next = (el); \ |
86 | 0 | (el)->prev = (after); \ |
87 | 0 | } else { /* after==0 = list head */ \ |
88 | 0 | (after) = (el); \ |
89 | 0 | (el)->next = (el)->prev = 0; \ |
90 | 0 | } \ |
91 | 0 | } while(0) |
92 | | |
93 | | |
94 | | #define sock_listrm(head, el) \ |
95 | 0 | do { \ |
96 | 0 | if(*(head) == (el)) \ |
97 | 0 | *(head) = (el)->next; \ |
98 | 0 | if((el)->next) \ |
99 | 0 | (el)->next->prev = (el)->prev; \ |
100 | 0 | if((el)->prev) \ |
101 | 0 | (el)->prev->next = (el)->next; \ |
102 | 0 | } while(0) |
103 | | |
104 | | |
105 | 0 | #define addr_info_listadd sock_listadd |
106 | | #define addr_info_listins sock_listins |
107 | 0 | #define addr_info_listrm sock_listrm |
108 | | |
109 | | /** |
110 | | * return the scope for IPv6 interface matching the ipval parameter |
111 | | * - needed for binding to link local IPv6 addresses |
112 | | */ |
113 | | unsigned int ipv6_get_netif_scope(char *ipval) |
114 | 0 | { |
115 | 0 | struct ifaddrs *netiflist = NULL; |
116 | 0 | struct ifaddrs *netif = NULL; |
117 | 0 | char ipaddr[NI_MAXHOST]; |
118 | 0 | unsigned int iscope = 0; |
119 | 0 | int i = 0; |
120 | 0 | int r = 0; |
121 | 0 | ip_addr_t *ipa = NULL; |
122 | 0 | ip_addr_t vaddr; |
123 | 0 | str ips; |
124 | |
|
125 | 0 | ips.s = ipval; |
126 | 0 | ips.len = strlen(ipval); |
127 | |
|
128 | 0 | ipa = str2ip6(&ips); |
129 | 0 | if(ipa == NULL) { |
130 | 0 | LM_ERR("could not parse ipv6 address: %s\n", ipval); |
131 | 0 | return 0; |
132 | 0 | } |
133 | 0 | memcpy(&vaddr, ipa, sizeof(ip_addr_t)); |
134 | 0 | ipa = NULL; |
135 | | |
136 | | /* walk over the list of all network interface addresses */ |
137 | 0 | if(getifaddrs(&netiflist) != 0) { |
138 | 0 | LM_ERR("failed to get network interfaces - errno: %d\n", errno); |
139 | 0 | return 0; |
140 | 0 | } |
141 | 0 | for(netif = netiflist; netif; netif = netif->ifa_next) { |
142 | | /* only active and ipv6 */ |
143 | 0 | if(netif->ifa_addr && (netif->ifa_flags & IFF_UP) |
144 | 0 | && netif->ifa_addr->sa_family == AF_INET6) { |
145 | 0 | r = getnameinfo(netif->ifa_addr, sizeof(struct sockaddr_in6), |
146 | 0 | ipaddr, sizeof(ipaddr), NULL, 0, NI_NUMERICHOST); |
147 | 0 | if(r != 0) { |
148 | 0 | LM_ERR("failed to get the name info - ret: %d\n", r); |
149 | 0 | goto done; |
150 | 0 | } |
151 | | /* strip the interface name after */ |
152 | 0 | for(i = 0; ipaddr[i]; i++) { |
153 | 0 | if(ipaddr[i] == '%') { |
154 | 0 | ipaddr[i] = '\0'; |
155 | 0 | break; |
156 | 0 | } |
157 | 0 | } |
158 | 0 | ips.s = ipaddr; |
159 | 0 | ips.len = strlen(ipaddr); |
160 | 0 | ipa = str2ip6(&ips); |
161 | 0 | if(ipa != NULL) { |
162 | | /* if the ips match, get scope index from interface name */ |
163 | 0 | if(ip_addr_cmp(&vaddr, ipa)) { |
164 | 0 | iscope = if_nametoindex(netif->ifa_name); |
165 | 0 | goto done; |
166 | 0 | } |
167 | 0 | } |
168 | 0 | } |
169 | 0 | } |
170 | | |
171 | 0 | done: |
172 | 0 | freeifaddrs(netiflist); |
173 | 0 | return iscope; |
174 | 0 | } |
175 | | |
176 | | inline static void addr_info_list_ins_lst( |
177 | | struct addr_info *lst, struct addr_info *after) |
178 | 0 | { |
179 | 0 | struct addr_info *l; |
180 | 0 | struct addr_info *n; |
181 | |
|
182 | 0 | if(lst) { |
183 | 0 | n = after->next; |
184 | 0 | after->next = lst; |
185 | 0 | lst->prev = after; |
186 | 0 | if(n) { |
187 | 0 | for(l = lst; l->next; l = l->next) |
188 | 0 | ; |
189 | 0 | l->next = n; |
190 | 0 | n->prev = l; |
191 | 0 | } |
192 | 0 | } |
193 | 0 | } |
194 | | |
195 | | |
196 | | /* protocol order, filled by init_proto_order() */ |
197 | | enum sip_protos nxt_proto[PROTO_LAST + 1] = { |
198 | | PROTO_UDP, PROTO_TCP, PROTO_TLS, PROTO_SCTP, 0}; |
199 | | /* Deliberately left PROTO_WS and PROTO_WSS out of this as they are just |
200 | | upgraded TCP and TLS connections */ |
201 | | |
202 | | |
203 | | /* another helper function, it just fills a struct addr_info |
204 | | * returns: 0 on success, -1 on error*/ |
205 | | static int init_addr_info(struct addr_info *a, char *name, enum si_flags flags) |
206 | 0 | { |
207 | |
|
208 | 0 | memset(a, 0, sizeof(*a)); |
209 | 0 | a->name.len = strlen(name); |
210 | 0 | a->name.s = pkg_malloc(a->name.len + 1); /* include \0 */ |
211 | 0 | if(a->name.s == 0) |
212 | 0 | goto error; |
213 | 0 | memcpy(a->name.s, name, a->name.len + 1); |
214 | 0 | a->flags = flags; |
215 | 0 | return 0; |
216 | 0 | error: |
217 | 0 | PKG_MEM_ERROR; |
218 | 0 | return -1; |
219 | 0 | } |
220 | | |
221 | | |
222 | | /* returns 0 on error, new addr_info_lst element on success */ |
223 | | static inline struct addr_info *new_addr_info(char *name, enum si_flags gf) |
224 | 0 | { |
225 | 0 | struct addr_info *al; |
226 | |
|
227 | 0 | al = pkg_malloc(sizeof(*al)); |
228 | 0 | if(al == 0) |
229 | 0 | goto error; |
230 | 0 | al->next = 0; |
231 | 0 | al->prev = 0; |
232 | 0 | if(init_addr_info(al, name, gf) != 0) |
233 | 0 | goto error; |
234 | 0 | return al; |
235 | 0 | error: |
236 | 0 | PKG_MEM_ERROR; |
237 | 0 | if(al) { |
238 | 0 | if(al->name.s) |
239 | 0 | pkg_free(al->name.s); |
240 | 0 | pkg_free(al); |
241 | 0 | } |
242 | 0 | return 0; |
243 | 0 | } |
244 | | |
245 | | |
246 | | static inline void free_addr_info(struct addr_info *a) |
247 | 0 | { |
248 | 0 | if(a) { |
249 | 0 | if(a->name.s) { |
250 | 0 | pkg_free(a->name.s); |
251 | 0 | a->name.s = 0; |
252 | 0 | } |
253 | 0 | pkg_free(a); |
254 | 0 | } |
255 | 0 | } |
256 | | |
257 | | |
258 | | static inline void free_addr_info_lst(struct addr_info **lst) |
259 | 0 | { |
260 | 0 | struct addr_info *a; |
261 | 0 | struct addr_info *tmp; |
262 | |
|
263 | 0 | a = *lst; |
264 | 0 | while(a) { |
265 | 0 | tmp = a; |
266 | 0 | a = a->next; |
267 | 0 | free_addr_info(tmp); |
268 | 0 | } |
269 | 0 | } |
270 | | |
271 | | |
272 | | /* adds a new add_info_lst element to the corresponding list |
273 | | * returns 0 on success, -1 on error */ |
274 | | static int new_addr_info2list(char *name, enum si_flags f, struct addr_info **l) |
275 | 0 | { |
276 | 0 | struct addr_info *al; |
277 | |
|
278 | 0 | al = new_addr_info(name, f); |
279 | 0 | if(al == 0) |
280 | 0 | goto error; |
281 | 0 | addr_info_listadd(l, al); |
282 | 0 | return 0; |
283 | 0 | error: |
284 | 0 | return -1; |
285 | 0 | } |
286 | | |
287 | | |
288 | | /* another helper function, it just creates a socket_info struct |
289 | | * allocates a si and a si->name in new pkg memory */ |
290 | | static inline struct socket_info *new_sock_info(char *name, |
291 | | struct name_lst *addr_l, unsigned short port, unsigned short proto, |
292 | | unsigned short useproto, char *usename, unsigned short useport, |
293 | | char *sockname, enum si_flags flags) |
294 | 0 | { |
295 | 0 | struct socket_info *si; |
296 | 0 | struct name_lst *n; |
297 | 0 | struct hostent *he; |
298 | 0 | char *p; |
299 | |
|
300 | 0 | si = (struct socket_info *)pkg_malloc(sizeof(struct socket_info)); |
301 | 0 | if(si == 0) |
302 | 0 | goto error; |
303 | 0 | memset(si, 0, sizeof(struct socket_info)); |
304 | 0 | si->socket = -1; |
305 | 0 | si->name.len = strlen(name); |
306 | 0 | si->name.s = (char *)pkg_malloc(si->name.len + 1); /* include \0 */ |
307 | 0 | if(si->name.s == 0) |
308 | 0 | goto error; |
309 | 0 | memcpy(si->name.s, name, si->name.len + 1); |
310 | | /* set port & proto */ |
311 | 0 | si->port_no = port; |
312 | 0 | si->proto = proto; |
313 | 0 | si->flags = flags; |
314 | 0 | si->addr_info_lst = 0; |
315 | 0 | for(n = addr_l; n; n = n->next) { |
316 | 0 | if(new_addr_info2list(n->name, n->flags, &si->addr_info_lst) != 0) { |
317 | 0 | LM_ERR("new_addr_info2list failed\n"); |
318 | 0 | goto error; |
319 | 0 | } |
320 | 0 | } |
321 | 0 | if(sockname != NULL) { |
322 | 0 | si->sockname.len = strlen(sockname); |
323 | 0 | si->sockname.s = |
324 | 0 | (char *)pkg_malloc(si->sockname.len + 1); /* include \0 */ |
325 | 0 | if(si->sockname.s == 0) { |
326 | 0 | goto error; |
327 | 0 | } |
328 | 0 | memcpy(si->sockname.s, sockname, si->sockname.len + 1); |
329 | 0 | } |
330 | 0 | if(usename != NULL) { |
331 | 0 | si->useinfo.name.len = strlen(usename); |
332 | 0 | si->useinfo.name.s = (char *)pkg_malloc(si->useinfo.name.len + 1); |
333 | 0 | if(si->useinfo.name.s == 0) |
334 | 0 | goto error; |
335 | 0 | strncpy(si->useinfo.name.s, usename, si->useinfo.name.len + 1); |
336 | 0 | if(usename[0] == '[' && usename[si->useinfo.name.len - 1] == ']') { |
337 | 0 | si->useinfo.address_str.len = si->useinfo.name.len - 2; |
338 | 0 | p = si->useinfo.name.s + 1; |
339 | 0 | } else { |
340 | 0 | si->useinfo.address_str.len = si->useinfo.name.len; |
341 | 0 | p = si->useinfo.name.s; |
342 | 0 | } |
343 | 0 | si->useinfo.proto = (useproto != PROTO_NONE) ? useproto : proto; |
344 | 0 | si->useinfo.address_str.s = |
345 | 0 | (char *)pkg_malloc(si->useinfo.address_str.len + 1); |
346 | 0 | if(si->useinfo.address_str.s == NULL) |
347 | 0 | goto error; |
348 | 0 | strncpy(si->useinfo.address_str.s, p, si->useinfo.address_str.len); |
349 | 0 | si->useinfo.address_str.s[si->useinfo.address_str.len] = '\0'; |
350 | |
|
351 | 0 | p = int2str(useport, &si->useinfo.port_no_str.len); |
352 | 0 | if(p == NULL) |
353 | 0 | goto error; |
354 | 0 | si->useinfo.port_no_str.s = |
355 | 0 | (char *)pkg_malloc(si->useinfo.port_no_str.len + 1); |
356 | 0 | if(si->useinfo.port_no_str.s == NULL) |
357 | 0 | goto error; |
358 | 0 | strncpy(si->useinfo.port_no_str.s, p, si->useinfo.port_no_str.len); |
359 | 0 | si->useinfo.port_no = useport; |
360 | |
|
361 | 0 | he = resolvehost(si->useinfo.name.s); |
362 | 0 | if(he == 0) { |
363 | 0 | LM_ERR("unable to resolve advertised name %s\n", |
364 | 0 | si->useinfo.name.s); |
365 | 0 | goto error; |
366 | 0 | } |
367 | 0 | hostent2ip_addr(&si->useinfo.address, he, 0); |
368 | 0 | } |
369 | 0 | return si; |
370 | 0 | error: |
371 | 0 | PKG_MEM_ERROR; |
372 | 0 | if(si) { |
373 | 0 | if(si->name.s) { |
374 | 0 | pkg_free(si->name.s); |
375 | 0 | } |
376 | 0 | if(si->sockname.s) { |
377 | 0 | pkg_free(si->sockname.s); |
378 | 0 | } |
379 | 0 | pkg_free(si); |
380 | 0 | } |
381 | 0 | return 0; |
382 | 0 | } |
383 | | |
384 | | |
385 | | /* delete a socket_info struct */ |
386 | | static void free_sock_info(struct socket_info *si) |
387 | 0 | { |
388 | 0 | if(si) { |
389 | 0 | if(si->name.s) |
390 | 0 | pkg_free(si->name.s); |
391 | 0 | if(si->address_str.s) |
392 | 0 | pkg_free(si->address_str.s); |
393 | 0 | if(si->port_no_str.s) |
394 | 0 | pkg_free(si->port_no_str.s); |
395 | 0 | if(si->addr_info_lst) |
396 | 0 | free_addr_info_lst(&si->addr_info_lst); |
397 | 0 | if(si->sock_str.s) |
398 | 0 | pkg_free(si->sock_str.s); |
399 | 0 | if(si->sockname.s) |
400 | 0 | pkg_free(si->sockname.s); |
401 | 0 | if(si->useinfo.name.s) |
402 | 0 | pkg_free(si->useinfo.name.s); |
403 | 0 | if(si->useinfo.port_no_str.s) |
404 | 0 | pkg_free(si->useinfo.port_no_str.s); |
405 | 0 | if(si->useinfo.sock_str.s) |
406 | 0 | pkg_free(si->useinfo.sock_str.s); |
407 | 0 | } |
408 | 0 | } |
409 | | |
410 | | |
411 | | char *get_valid_proto_name(unsigned short proto) |
412 | 0 | { |
413 | 0 | switch(proto) { |
414 | 0 | case PROTO_NONE: |
415 | 0 | return "*"; |
416 | 0 | case PROTO_UDP: |
417 | 0 | return "udp"; |
418 | 0 | #ifdef USE_TCP |
419 | 0 | case PROTO_TCP: |
420 | 0 | return "tcp"; |
421 | 0 | #endif |
422 | 0 | #ifdef USE_TLS |
423 | 0 | case PROTO_TLS: |
424 | 0 | return "tls"; |
425 | 0 | #endif |
426 | 0 | #ifdef USE_SCTP |
427 | 0 | case PROTO_SCTP: |
428 | 0 | return "sctp"; |
429 | 0 | #endif |
430 | 0 | default: |
431 | 0 | return "unknown"; |
432 | 0 | } |
433 | 0 | } |
434 | | |
435 | | /** Convert socket to its textual representation. |
436 | | * |
437 | | * This function converts the transport protocol, the IP address and the port |
438 | | * number in a comma delimited string of form proto:ip:port. The resulting |
439 | | * string is NOT zero terminated |
440 | | * |
441 | | * @param s is a pointer to the destination memory buffer |
442 | | * @param len is a pointer to an integer variable. Initially the variable |
443 | | * should contain the size of the buffer in s. The value of the variable |
444 | | * will be changed to the length of the resulting string on success and |
445 | | * to the desired size of the destination buffer if it is too small |
446 | | * @param si is a pointer to the socket_info structure to be printed |
447 | | * @return -1 on error and 0 on success |
448 | | */ |
449 | | int socket2str(char *s, int *len, struct socket_info *si) |
450 | 0 | { |
451 | 0 | return socketinfo2str(s, len, si, 0); |
452 | 0 | } |
453 | | |
454 | | int socketinfo2str(char *s, int *len, struct socket_info *si, int mode) |
455 | 0 | { |
456 | 0 | str proto; |
457 | 0 | int l; |
458 | |
|
459 | 0 | if(si->useinfo.proto != PROTO_NONE) { |
460 | 0 | proto.s = get_valid_proto_name(si->useinfo.proto); |
461 | 0 | } else { |
462 | 0 | proto.s = get_valid_proto_name(si->proto); |
463 | 0 | } |
464 | 0 | proto.len = strlen(proto.s); |
465 | |
|
466 | 0 | if(mode == 1) |
467 | 0 | l = proto.len + si->useinfo.name.len + si->useinfo.port_no_str.len + 2; |
468 | 0 | else |
469 | 0 | l = proto.len + si->address_str.len + si->port_no_str.len + 2; |
470 | |
|
471 | 0 | if(si->address.af == AF_INET6) |
472 | 0 | l += 2; |
473 | |
|
474 | 0 | if(*len < l) { |
475 | 0 | LM_ERR("Destionation buffer too short\n"); |
476 | 0 | *len = l; |
477 | 0 | return -1; |
478 | 0 | } |
479 | | |
480 | 0 | memcpy(s, proto.s, proto.len); |
481 | 0 | s += proto.len; |
482 | 0 | *s = ':'; |
483 | 0 | s++; |
484 | 0 | if(mode == 1) { |
485 | 0 | memcpy(s, si->useinfo.name.s, si->useinfo.name.len); |
486 | 0 | s += si->useinfo.name.len; |
487 | 0 | *s = ':'; |
488 | 0 | s++; |
489 | 0 | memcpy(s, si->useinfo.port_no_str.s, si->useinfo.port_no_str.len); |
490 | 0 | s += si->useinfo.port_no_str.len; |
491 | 0 | } else { |
492 | 0 | if(si->address.af == AF_INET6) { |
493 | 0 | *s = '['; |
494 | 0 | s++; |
495 | 0 | } |
496 | 0 | memcpy(s, si->address_str.s, si->address_str.len); |
497 | 0 | s += si->address_str.len; |
498 | 0 | if(si->address.af == AF_INET6) { |
499 | 0 | *s = ']'; |
500 | 0 | s++; |
501 | 0 | } |
502 | 0 | *s = ':'; |
503 | 0 | s++; |
504 | 0 | memcpy(s, si->port_no_str.s, si->port_no_str.len); |
505 | 0 | s += si->port_no_str.len; |
506 | 0 | } |
507 | |
|
508 | 0 | *len = l; |
509 | 0 | return 0; |
510 | 0 | } |
511 | | |
512 | | |
513 | | /* Fill si->sock_str with string representing the socket_info structure, |
514 | | * format of the string is 'proto:address:port'. Returns 0 on success and |
515 | | * negative number on failure. |
516 | | */ |
517 | | static int fix_sock_str(struct socket_info *si) |
518 | 0 | { |
519 | 0 | int len = MAX_SOCKET_STR; |
520 | |
|
521 | 0 | if(si->sock_str.s) |
522 | 0 | pkg_free(si->sock_str.s); |
523 | |
|
524 | 0 | si->sock_str.s = pkg_malloc(len + 1); |
525 | 0 | if(si->sock_str.s == NULL) { |
526 | 0 | PKG_MEM_ERROR; |
527 | 0 | return -1; |
528 | 0 | } |
529 | 0 | if(socketinfo2str(si->sock_str.s, &len, si, 0) < 0) { |
530 | 0 | BUG("fix_sock_str: Error in socket to str\n"); |
531 | 0 | return -1; |
532 | 0 | } |
533 | 0 | si->sock_str.s[len] = '\0'; |
534 | 0 | si->sock_str.len = len; |
535 | 0 | if(si->useinfo.name.s != NULL) { |
536 | 0 | len = MAX_SOCKET_ADVERTISE_STR; |
537 | |
|
538 | 0 | if(si->useinfo.sock_str.s) |
539 | 0 | pkg_free(si->useinfo.sock_str.s); |
540 | |
|
541 | 0 | si->useinfo.sock_str.s = pkg_malloc(len + 1); |
542 | 0 | if(si->useinfo.sock_str.s == NULL) { |
543 | 0 | PKG_MEM_ERROR; |
544 | 0 | return -1; |
545 | 0 | } |
546 | 0 | if(socketinfo2str(si->useinfo.sock_str.s, &len, si, 1) < 0) { |
547 | 0 | BUG("fix_sock_str: Error in socket to str\n"); |
548 | 0 | return -1; |
549 | 0 | } |
550 | 0 | si->useinfo.sock_str.s[len] = '\0'; |
551 | 0 | si->useinfo.sock_str.len = len; |
552 | 0 | } |
553 | 0 | return 0; |
554 | 0 | } |
555 | | |
556 | | |
557 | | /* returns 0 if support for the protocol is not compiled or if proto is |
558 | | invalid */ |
559 | | struct socket_info **get_sock_info_list(unsigned short proto) |
560 | 0 | { |
561 | |
|
562 | 0 | switch(proto) { |
563 | 0 | case PROTO_UDP: |
564 | 0 | return &udp_listen; |
565 | 0 | break; |
566 | 0 | case PROTO_TCP: |
567 | 0 | case PROTO_WS: |
568 | 0 | #ifdef USE_TCP |
569 | 0 | return &tcp_listen; |
570 | 0 | #endif |
571 | 0 | break; |
572 | 0 | case PROTO_TLS: |
573 | 0 | case PROTO_WSS: |
574 | 0 | #ifdef USE_TLS |
575 | 0 | return &tls_listen; |
576 | 0 | #endif |
577 | 0 | break; |
578 | 0 | case PROTO_SCTP: |
579 | 0 | #ifdef USE_SCTP |
580 | 0 | return &sctp_listen; |
581 | 0 | #endif |
582 | 0 | break; |
583 | 0 | default: |
584 | 0 | LM_CRIT("invalid proto %d\n", proto); |
585 | 0 | } |
586 | 0 | return 0; |
587 | 0 | } |
588 | | |
589 | | /* Check list of active local IPs for grep_sock_info |
590 | | * This function is only used for sockets with the SI_IS_VIRTUAL flag set. This |
591 | | * is so floating (virtual) IPs that are not currently local, are not returned |
592 | | * as matches by grep_sock_info. |
593 | | * |
594 | | * Params: |
595 | | * - si - Socket info of socket that has been flagged with SI_IS_VIRTUAL, |
596 | | * that we want to check if it's actually local right now. |
597 | | * |
598 | | * Returns 1 if socket is local, or 0 if not. |
599 | | */ |
600 | | static int check_local_addresses(struct socket_info *si) |
601 | 0 | { |
602 | 0 | int match = 0; |
603 | 0 | struct ifaddrs *ifap, *ifa; |
604 | |
|
605 | 0 | if(si == NULL) { |
606 | 0 | LM_ERR("Socket info is NULL. Returning no match.\n"); |
607 | 0 | return 0; |
608 | 0 | } |
609 | | |
610 | 0 | if(!(si->flags & SI_IS_VIRTUAL)) { |
611 | 0 | LM_ERR("Have been passed a socket without the virtual flag set. This " |
612 | 0 | "should " |
613 | 0 | "not happen. Returning a match to maintain standard " |
614 | 0 | "behaviour.\n"); |
615 | 0 | return 1; |
616 | 0 | } |
617 | | |
618 | 0 | if(getifaddrs(&ifap) != 0) { |
619 | 0 | LM_ERR("getifaddrs failed. Assuming no match.\n"); |
620 | 0 | return 0; |
621 | 0 | } |
622 | | |
623 | 0 | for(ifa = ifap; ifa; ifa = ifa->ifa_next) { |
624 | | /* skip if no IP addr associated with the interface */ |
625 | 0 | if(ifa->ifa_addr == 0) |
626 | 0 | continue; |
627 | 0 | #ifdef AF_PACKET |
628 | | /* skip AF_PACKET addr family since it is of no use later on */ |
629 | 0 | if(ifa->ifa_addr->sa_family == AF_PACKET) |
630 | 0 | continue; |
631 | 0 | #endif |
632 | 0 | struct ip_addr local_addr; |
633 | 0 | sockaddr2ip_addr(&local_addr, (struct sockaddr *)ifa->ifa_addr); |
634 | |
|
635 | 0 | LM_DBG("Checking local address: %s\n", ip_addr2a(&local_addr)); |
636 | 0 | if(ip_addr_cmp(&si->address, &local_addr)) { |
637 | 0 | match = 1; |
638 | 0 | LM_DBG("Found matching local IP %s for virtual socket %s\n", |
639 | 0 | ip_addr2a(&local_addr), si->name.s); |
640 | 0 | break; |
641 | 0 | } |
642 | 0 | } |
643 | 0 | freeifaddrs(ifap); |
644 | | //Default to not local if no match is found |
645 | 0 | if(!match) { |
646 | 0 | LM_DBG("No matching local IP found for socket %s.\n", si->name.s); |
647 | 0 | return 0; |
648 | 0 | } else { |
649 | 0 | return 1; |
650 | 0 | } |
651 | 0 | } |
652 | | |
653 | | /* helper function for grep_sock_info |
654 | | * params: |
655 | | * host - hostname to compare with |
656 | | * name - official name |
657 | | * addr_str - name's resolved ip address converted to string |
658 | | * ip_addr - name's ip address |
659 | | * flags - set to SI_IS_IP if name contains an IP |
660 | | * |
661 | | * returns 0 if host matches, -1 if not */ |
662 | | inline static int si_hname_cmp( |
663 | | str *host, str *name, str *addr_str, struct ip_addr *ip_addr, int flags) |
664 | 0 | { |
665 | 0 | struct ip_addr *ip6; |
666 | |
|
667 | 0 | if((host->len == name->len) |
668 | 0 | && (strncasecmp(host->s, name->s, name->len) == 0) /*slower*/) |
669 | | /* comp. must be case insensitive, host names |
670 | | * can be written in mixed case, it will also match |
671 | | * ipv6 addresses if we are lucky*/ |
672 | 0 | goto found; |
673 | | /* check if host == ip address */ |
674 | | /* ipv6 case is uglier, host can be [3ffe::1] */ |
675 | 0 | ip6 = str2ip6(host); |
676 | 0 | if(ip6) { |
677 | 0 | if(ip_addr_cmp(ip6, ip_addr)) |
678 | 0 | goto found; /* match */ |
679 | 0 | else |
680 | 0 | return -1; /* no match, but this is an ipv6 address |
681 | | so no point in trying ipv4 */ |
682 | 0 | } |
683 | | /* ipv4 */ |
684 | 0 | if((!(flags & SI_IS_IP)) && (host->len == addr_str->len) |
685 | 0 | && (memcmp(host->s, addr_str->s, addr_str->len) == 0)) |
686 | 0 | goto found; |
687 | 0 | return -1; |
688 | 0 | found: |
689 | 0 | return 0; |
690 | 0 | } |
691 | | |
692 | | |
693 | | /* checks if the proto: host:port is one of the address we listen on |
694 | | * and returns the corresponding socket_info structure. |
695 | | * if port==0, the port number is ignored |
696 | | * if proto==0 (PROTO_NONE) the protocol is ignored |
697 | | * returns 0 if not found |
698 | | * WARNING: uses str2ip6 so it will overwrite any previous |
699 | | * unsaved result of this function (static buffer) |
700 | | */ |
701 | | struct socket_info *grep_sock_info( |
702 | | str *host, unsigned short port, unsigned short proto) |
703 | 0 | { |
704 | 0 | str hname; |
705 | 0 | struct socket_info *si; |
706 | 0 | struct socket_info **list; |
707 | 0 | struct addr_info *ai; |
708 | 0 | unsigned short c_proto; |
709 | |
|
710 | 0 | hname = *host; |
711 | 0 | if((hname.len > 2) && ((*hname.s) == '[') |
712 | 0 | && (hname.s[hname.len - 1] == ']')) { |
713 | | /* ipv6 - skip [] */ |
714 | 0 | hname.s++; |
715 | 0 | hname.len -= 2; |
716 | 0 | } |
717 | |
|
718 | 0 | c_proto = (proto != PROTO_NONE) ? proto : PROTO_UDP; |
719 | 0 | retry: |
720 | 0 | do { |
721 | | /* get the proper sock_list */ |
722 | 0 | list = get_sock_info_list(c_proto); |
723 | |
|
724 | 0 | if(list == 0) { |
725 | | /* disabled or unknown protocol */ |
726 | 0 | continue; |
727 | 0 | } |
728 | 0 | for(si = *list; si; si = si->next) { |
729 | 0 | LM_DBG("checking if host==us: %d==%d && [%.*s] == [%.*s]\n", |
730 | 0 | hname.len, si->name.len, hname.len, hname.s, si->name.len, |
731 | 0 | si->name.s); |
732 | 0 | if(port) { |
733 | 0 | LM_DBG("checking if port %d (advertise %d) matches port %d\n", |
734 | 0 | si->port_no, si->useinfo.port_no, port); |
735 | 0 | if(si->port_no != port && si->useinfo.port_no != port) { |
736 | 0 | continue; |
737 | 0 | } |
738 | 0 | } |
739 | 0 | if(si_hname_cmp(&hname, &si->name, &si->address_str, &si->address, |
740 | 0 | si->flags) |
741 | 0 | == 0) { |
742 | 0 | if(si->flags & SI_IS_VIRTUAL) { |
743 | 0 | LM_DBG("Checking virtual socket: [%.*s]\n", si->name.len, |
744 | 0 | si->name.s); |
745 | 0 | if(check_local_addresses(si)) { |
746 | 0 | goto found; |
747 | 0 | } else { |
748 | 0 | LM_DBG("Skipping virtual socket that is not local.\n"); |
749 | 0 | } |
750 | 0 | } else { |
751 | 0 | goto found; |
752 | 0 | } |
753 | 0 | } |
754 | 0 | if(si->useinfo.name.s != NULL) { |
755 | 0 | LM_DBG("checking advertise if host==us:" |
756 | 0 | " %d==%d && [%.*s] == [%.*s]\n", |
757 | 0 | hname.len, si->useinfo.name.len, hname.len, hname.s, |
758 | 0 | si->useinfo.name.len, si->useinfo.name.s); |
759 | 0 | if(si_hname_cmp(&hname, &si->useinfo.name, |
760 | 0 | &si->useinfo.address_str, &si->useinfo.address, |
761 | 0 | si->flags) |
762 | 0 | == 0) { |
763 | 0 | goto found; |
764 | 0 | } |
765 | 0 | } |
766 | | /* try among the extra addresses */ |
767 | 0 | for(ai = si->addr_info_lst; ai; ai = ai->next) { |
768 | 0 | if(si_hname_cmp(&hname, &ai->name, &ai->address_str, |
769 | 0 | &ai->address, ai->flags) |
770 | 0 | == 0) { |
771 | 0 | goto found; |
772 | 0 | } |
773 | 0 | } |
774 | 0 | } |
775 | |
|
776 | 0 | } while((proto == 0) && (c_proto = next_proto(c_proto))); |
777 | | |
778 | 0 | #ifdef USE_TLS |
779 | 0 | if(unlikely(c_proto == PROTO_WS)) { |
780 | 0 | c_proto = PROTO_WSS; |
781 | 0 | goto retry; |
782 | 0 | } |
783 | 0 | #endif |
784 | | /* not_found: */ |
785 | 0 | return 0; |
786 | 0 | found: |
787 | 0 | return si; |
788 | 0 | } |
789 | | |
790 | | /** |
791 | | * |
792 | | */ |
793 | | static int _ksr_sockets_no = 0; |
794 | | |
795 | | /** |
796 | | * |
797 | | */ |
798 | | int ksr_sockets_no_get(void) |
799 | 0 | { |
800 | 0 | return _ksr_sockets_no; |
801 | 0 | } |
802 | | |
803 | | /** |
804 | | * |
805 | | */ |
806 | | void ksr_sockets_index(void) |
807 | 0 | { |
808 | 0 | socket_info_t *si = NULL; |
809 | 0 | struct socket_info **list; |
810 | 0 | unsigned short c_proto; |
811 | |
|
812 | 0 | if(_ksr_sockets_no > 0) { |
813 | 0 | return; |
814 | 0 | } |
815 | | |
816 | 0 | c_proto = PROTO_UDP; |
817 | 0 | do { |
818 | | /* get the proper sock_list */ |
819 | 0 | list = get_sock_info_list(c_proto); |
820 | |
|
821 | 0 | if(list == 0) { |
822 | | /* disabled or unknown protocol */ |
823 | 0 | continue; |
824 | 0 | } |
825 | | |
826 | 0 | for(si = *list; si; si = si->next) { |
827 | 0 | if(si->sockname.s == NULL) { |
828 | 0 | continue; |
829 | 0 | } |
830 | 0 | si->gindex = _ksr_sockets_no; |
831 | 0 | _ksr_sockets_no++; |
832 | 0 | } |
833 | 0 | } while((c_proto = next_proto(c_proto)) != 0); |
834 | | |
835 | 0 | LM_DBG("number of listen sockets: %d\n", _ksr_sockets_no); |
836 | 0 | } |
837 | | |
838 | | socket_info_t *ksr_get_socket_by_name(str *sockname) |
839 | 0 | { |
840 | 0 | socket_info_t *si = NULL; |
841 | 0 | struct socket_info **list; |
842 | 0 | unsigned short c_proto; |
843 | |
|
844 | 0 | c_proto = PROTO_UDP; |
845 | 0 | do { |
846 | | /* get the proper sock_list */ |
847 | 0 | list = get_sock_info_list(c_proto); |
848 | |
|
849 | 0 | if(list == 0) { |
850 | | /* disabled or unknown protocol */ |
851 | 0 | continue; |
852 | 0 | } |
853 | | |
854 | 0 | for(si = *list; si; si = si->next) { |
855 | 0 | if(si->sockname.s == NULL) { |
856 | 0 | continue; |
857 | 0 | } |
858 | 0 | LM_DBG("checking if sockname %.*s matches %.*s\n", sockname->len, |
859 | 0 | sockname->s, si->sockname.len, si->sockname.s); |
860 | 0 | if(sockname->len == si->sockname.len |
861 | 0 | && strncasecmp(sockname->s, si->sockname.s, sockname->len) |
862 | 0 | == 0) { |
863 | 0 | return si; |
864 | 0 | } |
865 | 0 | } |
866 | 0 | } while((c_proto = next_proto(c_proto)) != 0); |
867 | | |
868 | 0 | return NULL; |
869 | 0 | } |
870 | | |
871 | | socket_info_t *ksr_get_socket_by_listen(str *sockstr) |
872 | 0 | { |
873 | 0 | socket_info_t *si = NULL; |
874 | 0 | struct socket_info **list; |
875 | 0 | unsigned short c_proto; |
876 | |
|
877 | 0 | c_proto = PROTO_UDP; |
878 | 0 | do { |
879 | | /* get the proper sock_list */ |
880 | 0 | list = get_sock_info_list(c_proto); |
881 | |
|
882 | 0 | if(list == 0) { |
883 | | /* disabled or unknown protocol */ |
884 | 0 | continue; |
885 | 0 | } |
886 | | |
887 | 0 | for(si = *list; si; si = si->next) { |
888 | 0 | if(si->sock_str.s == NULL) { |
889 | 0 | continue; |
890 | 0 | } |
891 | 0 | LM_DBG("checking if listen %.*s matches %.*s\n", sockstr->len, |
892 | 0 | sockstr->s, si->sock_str.len, si->sock_str.s); |
893 | 0 | if(sockstr->len == si->sock_str.len |
894 | 0 | && strncasecmp(sockstr->s, si->sock_str.s, sockstr->len) |
895 | 0 | == 0) { |
896 | 0 | return si; |
897 | 0 | } |
898 | 0 | } |
899 | 0 | } while((c_proto = next_proto(c_proto)) != 0); |
900 | | |
901 | 0 | return NULL; |
902 | 0 | } |
903 | | |
904 | | socket_info_t *ksr_get_socket_by_advertise(str *sockstr) |
905 | 0 | { |
906 | 0 | socket_info_t *si = NULL; |
907 | 0 | struct socket_info **list; |
908 | 0 | unsigned short c_proto; |
909 | |
|
910 | 0 | c_proto = PROTO_UDP; |
911 | 0 | do { |
912 | | /* get the proper sock_list */ |
913 | 0 | list = get_sock_info_list(c_proto); |
914 | |
|
915 | 0 | if(list == 0) { |
916 | | /* disabled or unknown protocol */ |
917 | 0 | continue; |
918 | 0 | } |
919 | | |
920 | 0 | for(si = *list; si; si = si->next) { |
921 | 0 | if(si->useinfo.sock_str.s == NULL) { |
922 | 0 | continue; |
923 | 0 | } |
924 | 0 | LM_DBG("checking if listen %.*s matches %.*s\n", sockstr->len, |
925 | 0 | sockstr->s, si->useinfo.sock_str.len, |
926 | 0 | si->useinfo.sock_str.s); |
927 | 0 | if(sockstr->len == si->useinfo.sock_str.len |
928 | 0 | && strncasecmp( |
929 | 0 | sockstr->s, si->useinfo.sock_str.s, sockstr->len) |
930 | 0 | == 0) { |
931 | 0 | return si; |
932 | 0 | } |
933 | 0 | } |
934 | 0 | } while((c_proto = next_proto(c_proto)) != 0); |
935 | | |
936 | 0 | return NULL; |
937 | 0 | } |
938 | | |
939 | | socket_info_t *ksr_get_socket_by_index(int idx) |
940 | 0 | { |
941 | 0 | socket_info_t *si = NULL; |
942 | 0 | struct socket_info **list; |
943 | 0 | unsigned short c_proto; |
944 | |
|
945 | 0 | if(idx < 0) { |
946 | 0 | idx += _ksr_sockets_no; |
947 | 0 | if(idx < 0) { |
948 | 0 | LM_DBG("negative overall index\n"); |
949 | 0 | return NULL; |
950 | 0 | } |
951 | 0 | } |
952 | 0 | c_proto = PROTO_UDP; |
953 | 0 | do { |
954 | | /* get the proper sock_list */ |
955 | 0 | list = get_sock_info_list(c_proto); |
956 | |
|
957 | 0 | if(list == 0) { |
958 | | /* disabled or unknown protocol */ |
959 | 0 | continue; |
960 | 0 | } |
961 | | |
962 | 0 | for(si = *list; si; si = si->next) { |
963 | 0 | if(idx == 0) { |
964 | 0 | return si; |
965 | 0 | } |
966 | 0 | idx--; |
967 | 0 | } |
968 | 0 | } while((c_proto = next_proto(c_proto)) != 0); |
969 | | |
970 | 0 | return NULL; |
971 | 0 | } |
972 | | |
973 | | socket_info_t *ksr_get_socket_by_address(str *sockstr) |
974 | 0 | { |
975 | 0 | socket_info_t *si = NULL; |
976 | |
|
977 | 0 | si = ksr_get_socket_by_listen(sockstr); |
978 | |
|
979 | 0 | if(si != NULL) { |
980 | 0 | return si; |
981 | 0 | } |
982 | | |
983 | 0 | return ksr_get_socket_by_advertise(sockstr); |
984 | 0 | } |
985 | | |
986 | | /* checks if the proto:port is one of the ports we listen on |
987 | | * and returns the corresponding socket_info structure. |
988 | | * if proto==0 (PROTO_NONE) the protocol is ignored |
989 | | * returns 0 if not found |
990 | | */ |
991 | | struct socket_info *grep_sock_info_by_port( |
992 | | unsigned short port, unsigned short proto) |
993 | 0 | { |
994 | 0 | struct socket_info *si; |
995 | 0 | struct socket_info **list; |
996 | 0 | unsigned short c_proto; |
997 | |
|
998 | 0 | if(!port) { |
999 | 0 | goto not_found; |
1000 | 0 | } |
1001 | 0 | c_proto = (proto != PROTO_NONE) ? proto : PROTO_UDP; |
1002 | 0 | do { |
1003 | | /* get the proper sock_list */ |
1004 | 0 | list = get_sock_info_list(c_proto); |
1005 | |
|
1006 | 0 | if(list == 0) /* disabled or unknown protocol */ |
1007 | 0 | continue; |
1008 | | |
1009 | 0 | for(si = *list; si; si = si->next) { |
1010 | 0 | LM_DBG("checking if port %d matches port %d\n", si->port_no, port); |
1011 | 0 | if(si->port_no == port) { |
1012 | 0 | goto found; |
1013 | 0 | } |
1014 | 0 | } |
1015 | 0 | } while((proto == 0) && (c_proto = next_proto(c_proto))); |
1016 | | |
1017 | 0 | not_found: |
1018 | 0 | return 0; |
1019 | | |
1020 | 0 | found: |
1021 | 0 | return si; |
1022 | 0 | } |
1023 | | |
1024 | | |
1025 | | /* checks if the proto: ip:port is one of the address we listen on |
1026 | | * and returns the corresponding socket_info structure. |
1027 | | * (same as grep_socket_info, but use ip addr instead) |
1028 | | * if port==0, the port number is ignored |
1029 | | * if proto==0 (PROTO_NONE) the protocol is ignored |
1030 | | * returns 0 if not found |
1031 | | * WARNING: uses str2ip6 so it will overwrite any previous |
1032 | | * unsaved result of this function (static buffer) |
1033 | | */ |
1034 | | struct socket_info *find_si( |
1035 | | struct ip_addr *ip, unsigned short port, unsigned short proto) |
1036 | 0 | { |
1037 | 0 | struct socket_info *si; |
1038 | 0 | struct socket_info **list; |
1039 | 0 | struct addr_info *ai; |
1040 | 0 | unsigned short c_proto; |
1041 | |
|
1042 | 0 | c_proto = (proto != PROTO_NONE) ? proto : PROTO_UDP; |
1043 | 0 | do { |
1044 | | /* get the proper sock_list */ |
1045 | 0 | list = get_sock_info_list(c_proto); |
1046 | |
|
1047 | 0 | if(list == 0) /* disabled or unknown protocol */ |
1048 | 0 | continue; |
1049 | | |
1050 | 0 | for(si = *list; si; si = si->next) { |
1051 | 0 | if(port) { |
1052 | 0 | if(si->port_no != port) { |
1053 | 0 | continue; |
1054 | 0 | } |
1055 | 0 | } |
1056 | 0 | if(ip_addr_cmp(ip, &si->address) |
1057 | 0 | || ip_addr_cmp(ip, &si->useinfo.address)) |
1058 | 0 | goto found; |
1059 | 0 | for(ai = si->addr_info_lst; ai; ai = ai->next) |
1060 | 0 | if(ip_addr_cmp(ip, &ai->address)) |
1061 | 0 | goto found; |
1062 | 0 | } |
1063 | 0 | } while((proto == 0) && (c_proto = next_proto(c_proto))); |
1064 | | /* not_found: */ |
1065 | 0 | return 0; |
1066 | 0 | found: |
1067 | 0 | return si; |
1068 | 0 | } |
1069 | | |
1070 | | |
1071 | | /* append a new sock_info structure to the corresponding list |
1072 | | * return new sock info on success, 0 on error */ |
1073 | | static struct socket_info *new_sock2list(char *name, struct name_lst *addr_l, |
1074 | | unsigned short port, unsigned short proto, unsigned short useproto, |
1075 | | char *usename, unsigned short useport, char *sockname, |
1076 | | enum si_flags flags, struct socket_info **list) |
1077 | 0 | { |
1078 | 0 | struct socket_info *si; |
1079 | | /* allocates si and si->name in new pkg memory */ |
1080 | 0 | si = new_sock_info(name, addr_l, port, proto, useproto, usename, useport, |
1081 | 0 | sockname, flags); |
1082 | 0 | if(si == 0) { |
1083 | 0 | LM_ERR("new_sock_info failed\n"); |
1084 | 0 | goto error; |
1085 | 0 | } |
1086 | 0 | if(socket_workers > 0) { |
1087 | 0 | si->workers = socket_workers; |
1088 | 0 | socket_workers = 0; |
1089 | 0 | } |
1090 | 0 | #ifdef USE_MCAST |
1091 | 0 | if(mcast != 0) { |
1092 | 0 | si->mcast.len = strlen(mcast); |
1093 | 0 | si->mcast.s = (char *)pkg_mallocxz(si->mcast.len + 1); |
1094 | 0 | if(si->mcast.s == 0) { |
1095 | 0 | PKG_MEM_ERROR; |
1096 | 0 | si->mcast.len = 0; |
1097 | 0 | pkg_free(si->name.s); |
1098 | 0 | pkg_free(si); |
1099 | 0 | return 0; |
1100 | 0 | } |
1101 | 0 | memcpy(si->mcast.s, mcast, si->mcast.len); |
1102 | 0 | mcast = 0; |
1103 | 0 | } |
1104 | 0 | #endif /* USE_MCAST */ |
1105 | 0 | sock_listadd(list, si); |
1106 | 0 | return si; |
1107 | 0 | error: |
1108 | 0 | return 0; |
1109 | 0 | } |
1110 | | |
1111 | | |
1112 | | /* adds a new sock_info structure immediately after "after" |
1113 | | * return new sock info on success, 0 on error */ |
1114 | | static struct socket_info *new_sock2list_after(char *name, |
1115 | | struct name_lst *addr_l, unsigned short port, unsigned short proto, |
1116 | | unsigned short useproto, char *usename, unsigned short useport, |
1117 | | char *sockname, enum si_flags flags, struct socket_info *after) |
1118 | 0 | { |
1119 | 0 | struct socket_info *si; |
1120 | |
|
1121 | 0 | si = new_sock_info(name, addr_l, port, proto, useproto, usename, useport, |
1122 | 0 | sockname, flags); |
1123 | 0 | if(si == 0) { |
1124 | 0 | LM_ERR("new_sock_info failed\n"); |
1125 | 0 | goto error; |
1126 | 0 | } |
1127 | 0 | sock_listins(si, after); |
1128 | 0 | return si; |
1129 | 0 | error: |
1130 | 0 | return 0; |
1131 | 0 | } |
1132 | | |
1133 | | |
1134 | | /* adds a sock_info structure to the corresponding proto list |
1135 | | * return last new socket info structur on success, NULL on error */ |
1136 | | socket_info_t *add_listen_socket_info(char *name, struct name_lst *addr_l, |
1137 | | unsigned short port, unsigned short proto, unsigned short useproto, |
1138 | | char *usename, unsigned short useport, char *sockname, |
1139 | | enum si_flags flags) |
1140 | 0 | { |
1141 | 0 | socket_info_t *newsi = NULL; |
1142 | 0 | socket_info_t **list = NULL; |
1143 | 0 | unsigned short c_proto; |
1144 | 0 | struct name_lst *a_l; |
1145 | 0 | unsigned short c_port; |
1146 | |
|
1147 | 0 | c_proto = (proto != PROTO_NONE) ? proto : PROTO_UDP; |
1148 | 0 | do { |
1149 | 0 | list = get_sock_info_list(c_proto); |
1150 | 0 | if(list == 0) /* disabled or unknown protocol */ |
1151 | 0 | continue; |
1152 | | |
1153 | 0 | if(port == 0) { /* use default port */ |
1154 | 0 | c_port = |
1155 | 0 | #ifdef USE_TLS |
1156 | 0 | ((c_proto) == PROTO_TLS) ? tls_port_no : |
1157 | 0 | #endif |
1158 | 0 | port_no; |
1159 | 0 | } |
1160 | 0 | #ifdef USE_TLS |
1161 | 0 | else if((c_proto == PROTO_TLS) && (proto == 0)) { |
1162 | | /* -l ip:port => on udp:ip:port; tcp:ip:port and tls:ip:port+1?*/ |
1163 | 0 | c_port = port + 1; |
1164 | 0 | } |
1165 | 0 | #endif |
1166 | 0 | else { |
1167 | 0 | c_port = port; |
1168 | 0 | } |
1169 | 0 | if(c_proto != PROTO_SCTP) { |
1170 | 0 | newsi = new_sock2list(name, 0, c_port, c_proto, useproto, usename, |
1171 | 0 | useport, sockname, flags & ~SI_IS_MHOMED, list); |
1172 | 0 | if(newsi == 0) { |
1173 | 0 | LM_ERR("new_sock2list failed\n"); |
1174 | 0 | goto error; |
1175 | 0 | } |
1176 | | /* add the other addresses in the list as separate sockets |
1177 | | * since only SCTP can bind to multiple addresses */ |
1178 | 0 | for(a_l = addr_l; a_l; a_l = a_l->next) { |
1179 | 0 | if(new_sock2list(a_l->name, 0, c_port, c_proto, useproto, |
1180 | 0 | usename, useport, sockname, flags & ~SI_IS_MHOMED, |
1181 | 0 | list) |
1182 | 0 | == 0) { |
1183 | 0 | LM_ERR("new_sock2list failed\n"); |
1184 | 0 | goto error; |
1185 | 0 | } |
1186 | 0 | } |
1187 | 0 | } else { |
1188 | 0 | newsi = new_sock2list(name, addr_l, c_port, c_proto, useproto, |
1189 | 0 | usename, useport, sockname, flags, list); |
1190 | 0 | if(newsi == 0) { |
1191 | 0 | LM_ERR("new_sock2list failed\n"); |
1192 | 0 | goto error; |
1193 | 0 | } |
1194 | 0 | } |
1195 | 0 | } while((proto == 0) && (c_proto = next_proto(c_proto))); |
1196 | | |
1197 | 0 | return newsi; |
1198 | 0 | error: |
1199 | 0 | return NULL; |
1200 | 0 | } |
1201 | | |
1202 | | /* adds a sock_info structure to the corresponding proto list |
1203 | | * return 0 on success, -1 on error */ |
1204 | | int add_listen_advertise_iface_name(char *name, struct name_lst *addr_l, |
1205 | | unsigned short port, unsigned short proto, unsigned short useproto, |
1206 | | char *usename, unsigned short useport, char *sockname, |
1207 | | enum si_flags flags) |
1208 | 0 | { |
1209 | 0 | if(add_listen_socket_info(name, addr_l, port, proto, useproto, usename, |
1210 | 0 | useport, sockname, flags) |
1211 | 0 | == NULL) { |
1212 | 0 | return -1; |
1213 | 0 | } |
1214 | 0 | return 0; |
1215 | 0 | } |
1216 | | |
1217 | | /* adds a sock_info structure to the corresponding proto list |
1218 | | * return 0 on success, -1 on error */ |
1219 | | int add_listen_advertise_iface(char *name, struct name_lst *addr_l, |
1220 | | unsigned short port, unsigned short proto, unsigned short useproto, |
1221 | | char *usename, unsigned short useport, enum si_flags flags) |
1222 | 0 | { |
1223 | 0 | return add_listen_advertise_iface_name( |
1224 | 0 | name, addr_l, port, proto, useproto, usename, useport, NULL, flags); |
1225 | 0 | } |
1226 | | |
1227 | | /* adds a sock_info structure to the corresponding proto list |
1228 | | * return 0 on success, -1 on error */ |
1229 | | int add_listen_iface(char *name, struct name_lst *addr_l, unsigned short port, |
1230 | | unsigned short proto, enum si_flags flags) |
1231 | 0 | { |
1232 | 0 | return add_listen_advertise_iface_name( |
1233 | 0 | name, addr_l, port, proto, 0, 0, 0, 0, flags); |
1234 | 0 | } |
1235 | | |
1236 | | /* adds a sock_info structure to the corresponding proto list |
1237 | | * return 0 on success, -1 on error */ |
1238 | | int add_listen_iface_name(char *name, struct name_lst *addr_l, |
1239 | | unsigned short port, unsigned short proto, char *sockname, |
1240 | | enum si_flags flags) |
1241 | 0 | { |
1242 | 0 | return add_listen_advertise_iface_name( |
1243 | 0 | name, addr_l, port, proto, 0, 0, 0, sockname, flags); |
1244 | 0 | } |
1245 | | |
1246 | | int add_listen_socket(socket_attrs_t *sa) |
1247 | 0 | { |
1248 | 0 | socket_info_t *newsi; |
1249 | 0 | name_lst_t addr_l; |
1250 | |
|
1251 | 0 | if(sa->bindaddr.s == NULL) { |
1252 | 0 | LM_ERR("no bind address provided\n"); |
1253 | 0 | return -1; |
1254 | 0 | } |
1255 | 0 | memset(&addr_l, 0, sizeof(name_lst_t)); |
1256 | 0 | addr_l.name = sa->bindaddr.s; |
1257 | |
|
1258 | 0 | newsi = add_listen_socket_info(sa->bindaddr.s, &addr_l, sa->bindport, |
1259 | 0 | sa->bindproto, sa->useproto, sa->useaddr.s, sa->useport, |
1260 | 0 | sa->sockname.s, sa->sflags); |
1261 | |
|
1262 | 0 | return (newsi != NULL) ? 0 : -1; |
1263 | 0 | } |
1264 | | |
1265 | | #ifdef __OS_linux |
1266 | | |
1267 | | #include "linux/types.h" |
1268 | | #include "linux/netlink.h" |
1269 | | #include "linux/rtnetlink.h" |
1270 | | #include "arpa/inet.h" |
1271 | | |
1272 | | |
1273 | 0 | #define MAX_IF_LEN 64 |
1274 | | struct idx |
1275 | | { |
1276 | | struct idx *next; |
1277 | | int family; |
1278 | | unsigned ifa_flags; |
1279 | | char addr[MAX_IF_LEN]; |
1280 | | }; |
1281 | | |
1282 | | struct idxlist |
1283 | | { |
1284 | | struct idx *addresses; |
1285 | | int index; |
1286 | | char name[MAX_IF_LEN]; |
1287 | | unsigned flags; |
1288 | | }; |
1289 | | |
1290 | 0 | #define MAX_IFACE_NO 32 |
1291 | | |
1292 | | static struct idxlist *ifaces = NULL; |
1293 | | static int seq = 0; |
1294 | | |
1295 | | #define SADDR(s) ((struct sockaddr_in *)s)->sin_addr.s_addr |
1296 | | |
1297 | | #define NLMSG_TAIL(nmsg) \ |
1298 | 0 | ((struct rtattr *)(((void *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) |
1299 | | |
1300 | | int addattr_l( |
1301 | | struct nlmsghdr *n, int maxlen, int type, const void *data, int alen) |
1302 | 0 | { |
1303 | 0 | int len = RTA_LENGTH(alen); |
1304 | 0 | struct rtattr *rta; |
1305 | |
|
1306 | 0 | if(NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { |
1307 | 0 | fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n", |
1308 | 0 | maxlen); |
1309 | 0 | return -1; |
1310 | 0 | } |
1311 | 0 | rta = NLMSG_TAIL(n); |
1312 | 0 | rta->rta_type = type; |
1313 | 0 | rta->rta_len = len; |
1314 | 0 | memcpy(RTA_DATA(rta), data, alen); |
1315 | 0 | n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); |
1316 | 0 | return 0; |
1317 | 0 | } |
1318 | | |
1319 | | |
1320 | | static int nl_bound_sock(void) |
1321 | 0 | { |
1322 | 0 | int sock = -1; |
1323 | 0 | struct sockaddr_nl la; |
1324 | |
|
1325 | 0 | sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); |
1326 | 0 | if(sock < 0) { |
1327 | 0 | LM_ERR("could not create NETLINK sock to get interface list\n"); |
1328 | 0 | goto error; |
1329 | 0 | } |
1330 | | |
1331 | | /* bind NETLINK socket to pid */ |
1332 | 0 | bzero(&la, sizeof(la)); |
1333 | 0 | la.nl_family = AF_NETLINK; |
1334 | 0 | la.nl_pad = 0; |
1335 | 0 | la.nl_pid = getpid(); |
1336 | 0 | la.nl_groups = 0; |
1337 | 0 | if(bind(sock, (struct sockaddr *)&la, sizeof(la)) < 0) { |
1338 | 0 | LM_ERR("could not bind NETLINK sock to sockaddr_nl\n"); |
1339 | 0 | goto error; |
1340 | 0 | } |
1341 | | |
1342 | 0 | return sock; |
1343 | 0 | error: |
1344 | 0 | if(sock >= 0) |
1345 | 0 | close(sock); |
1346 | 0 | return -1; |
1347 | 0 | } |
1348 | | |
1349 | | #define fill_nl_req(req, type, family) \ |
1350 | 0 | do { \ |
1351 | 0 | memset(&req, 0, sizeof(req)); \ |
1352 | 0 | req.nlh.nlmsg_len = sizeof(req); \ |
1353 | 0 | req.nlh.nlmsg_type = type; \ |
1354 | 0 | req.nlh.nlmsg_flags = \ |
1355 | 0 | NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST | NLM_F_DUMP; \ |
1356 | 0 | req.nlh.nlmsg_pid = getpid(); \ |
1357 | 0 | req.nlh.nlmsg_seq = seq++; \ |
1358 | 0 | req.g.rtgen_family = family; \ |
1359 | 0 | } while(0); |
1360 | | |
1361 | | #define NETLINK_BUFFER_SIZE 32768 |
1362 | | |
1363 | | static int get_flags(int family) |
1364 | 0 | { |
1365 | 0 | struct |
1366 | 0 | { |
1367 | 0 | struct nlmsghdr nlh; |
1368 | 0 | struct rtgenmsg g; |
1369 | 0 | } req; |
1370 | 0 | int rtn = 0; |
1371 | 0 | struct nlmsghdr *nlp; |
1372 | 0 | struct ifinfomsg *ifi; |
1373 | 0 | char buf[NETLINK_BUFFER_SIZE]; |
1374 | 0 | char *p = buf; |
1375 | 0 | int nll = 0; |
1376 | 0 | int nl_sock = -1; |
1377 | |
|
1378 | 0 | fill_nl_req(req, RTM_GETLINK, family); |
1379 | |
|
1380 | 0 | if((nl_sock = nl_bound_sock()) < 0) |
1381 | 0 | return -1; |
1382 | | |
1383 | 0 | if(send(nl_sock, (void *)&req, sizeof(req), 0) < 0) { |
1384 | 0 | LM_ERR("error sending NETLINK request\n"); |
1385 | 0 | goto error; |
1386 | 0 | } |
1387 | | |
1388 | 0 | while(1) { |
1389 | 0 | if((sizeof(buf) - nll) == 0) { |
1390 | 0 | LM_ERR("netlink buffer overflow in get_flags"); |
1391 | 0 | goto error; |
1392 | 0 | } |
1393 | 0 | rtn = recv(nl_sock, p, sizeof(buf) - nll, 0); |
1394 | 0 | nlp = (struct nlmsghdr *)p; |
1395 | 0 | if(nlp->nlmsg_type == NLMSG_DONE) { |
1396 | 0 | LM_DBG("done\n"); |
1397 | 0 | break; |
1398 | 0 | } |
1399 | 0 | if(nlp->nlmsg_type == NLMSG_ERROR) { |
1400 | 0 | LM_DBG("Error on message to netlink"); |
1401 | 0 | break; |
1402 | 0 | } |
1403 | 0 | p += rtn; |
1404 | |
|
1405 | 0 | nll += rtn; |
1406 | 0 | } |
1407 | | |
1408 | 0 | nlp = (struct nlmsghdr *)buf; |
1409 | 0 | for(; NLMSG_OK(nlp, nll); nlp = NLMSG_NEXT(nlp, nll)) { |
1410 | 0 | ifi = NLMSG_DATA(nlp); |
1411 | |
|
1412 | 0 | if(nlp->nlmsg_len < NLMSG_LENGTH(sizeof(ifi))) |
1413 | 0 | goto error; |
1414 | | |
1415 | 0 | LM_ERR("Interface with index %d has flags %d\n", ifi->ifi_index, |
1416 | 0 | ifi->ifi_flags); |
1417 | 0 | if(ifaces == NULL) { |
1418 | 0 | LM_ERR("get_flags must not be called on empty interface list"); |
1419 | 0 | goto error; |
1420 | 0 | } |
1421 | 0 | if(ifi->ifi_index >= MAX_IFACE_NO) { |
1422 | 0 | LM_ERR("invalid network interface index returned %d", |
1423 | 0 | ifi->ifi_index); |
1424 | 0 | goto error; |
1425 | 0 | } |
1426 | 0 | ifaces[ifi->ifi_index].flags = ifi->ifi_flags; |
1427 | 0 | } |
1428 | | |
1429 | 0 | if(nl_sock >= 0) |
1430 | 0 | close(nl_sock); |
1431 | 0 | return 0; |
1432 | | |
1433 | 0 | error: |
1434 | 0 | if(nl_sock >= 0) |
1435 | 0 | close(nl_sock); |
1436 | 0 | return -1; |
1437 | 0 | } |
1438 | | |
1439 | | static int build_iface_list(void) |
1440 | 0 | { |
1441 | 0 | struct |
1442 | 0 | { |
1443 | 0 | struct nlmsghdr nlh; |
1444 | 0 | struct rtgenmsg g; |
1445 | 0 | } req; |
1446 | |
|
1447 | 0 | int rtn = 0; |
1448 | 0 | struct nlmsghdr *nlp; |
1449 | 0 | struct ifaddrmsg *ifi; |
1450 | 0 | int rtl; |
1451 | 0 | char buf[NETLINK_BUFFER_SIZE]; |
1452 | 0 | char *p = buf; |
1453 | 0 | int nll = 0; |
1454 | 0 | struct rtattr *rtap; |
1455 | 0 | int index, i; |
1456 | 0 | struct idx *entry; |
1457 | 0 | struct idx *tmp; |
1458 | 0 | int nl_sock = -1; |
1459 | 0 | int families[] = {AF_INET, AF_INET6}; |
1460 | 0 | char name[MAX_IF_LEN]; |
1461 | 0 | int is_link_local = 0; |
1462 | |
|
1463 | 0 | if(ifaces == NULL) { |
1464 | 0 | if((ifaces = (struct idxlist *)pkg_malloc( |
1465 | 0 | MAX_IFACE_NO * sizeof(struct idxlist))) |
1466 | 0 | == NULL) { |
1467 | 0 | PKG_MEM_ERROR; |
1468 | 0 | return -1; |
1469 | 0 | } |
1470 | 0 | memset(ifaces, 0, sizeof(struct idxlist) * MAX_IFACE_NO); |
1471 | 0 | } |
1472 | | |
1473 | | /* bind netlink socket */ |
1474 | 0 | if((nl_sock = nl_bound_sock()) < 0) |
1475 | 0 | return -1; |
1476 | | |
1477 | 0 | for(i = 0; i < sizeof(families) / sizeof(int); i++) { |
1478 | 0 | fill_nl_req(req, RTM_GETADDR, families[i]); |
1479 | |
|
1480 | 0 | if(send(nl_sock, (void *)&req, sizeof(req), 0) < 0) { |
1481 | 0 | LM_ERR("error sending NETLINK request\n"); |
1482 | 0 | goto error; |
1483 | 0 | }; |
1484 | |
|
1485 | 0 | memset(buf, 0, sizeof(buf)); |
1486 | 0 | nll = 0; |
1487 | 0 | p = buf; |
1488 | 0 | while(1) { |
1489 | 0 | if((sizeof(buf) - nll) == 0) { |
1490 | 0 | LM_ERR("netlink buffer overflow in build_iface_list"); |
1491 | 0 | goto error; |
1492 | 0 | } |
1493 | 0 | rtn = recv(nl_sock, p, sizeof(buf) - nll, 0); |
1494 | 0 | LM_DBG("received %d byles \n", rtn); |
1495 | 0 | nlp = (struct nlmsghdr *)p; |
1496 | 0 | if(nlp->nlmsg_type == NLMSG_DONE) { |
1497 | 0 | LM_DBG("done receiving netlink info \n"); |
1498 | 0 | break; |
1499 | 0 | } |
1500 | 0 | if(nlp->nlmsg_type == NLMSG_ERROR) { |
1501 | 0 | LM_ERR("Error on message to netlink"); |
1502 | 0 | break; |
1503 | 0 | } |
1504 | 0 | p += rtn; |
1505 | |
|
1506 | 0 | nll += rtn; |
1507 | 0 | } |
1508 | | |
1509 | 0 | nlp = (struct nlmsghdr *)buf; |
1510 | 0 | for(; NLMSG_OK(nlp, nll); nlp = NLMSG_NEXT(nlp, nll)) { |
1511 | 0 | ifi = NLMSG_DATA(nlp); |
1512 | |
|
1513 | 0 | if(nlp->nlmsg_len < NLMSG_LENGTH(sizeof(ifi))) |
1514 | 0 | continue; |
1515 | | // init all the strings |
1516 | | // inner loop: loop thru all the attributes of |
1517 | | // one route entry |
1518 | 0 | rtap = (struct rtattr *)IFA_RTA(ifi); |
1519 | |
|
1520 | 0 | rtl = IFA_PAYLOAD(nlp); |
1521 | |
|
1522 | 0 | index = ifi->ifa_index; |
1523 | 0 | if(index >= MAX_IFACE_NO) { |
1524 | 0 | LM_ERR("Invalid interface index returned: %d\n", index); |
1525 | 0 | goto error; |
1526 | 0 | } |
1527 | | |
1528 | 0 | entry = (struct idx *)pkg_malloc(sizeof(struct idx)); |
1529 | 0 | if(entry == 0) { |
1530 | 0 | PKG_MEM_ERROR; |
1531 | 0 | goto error; |
1532 | 0 | } |
1533 | | |
1534 | 0 | entry->next = 0; |
1535 | 0 | entry->family = families[i]; |
1536 | 0 | entry->ifa_flags = ifi->ifa_flags; |
1537 | 0 | is_link_local = 0; |
1538 | |
|
1539 | 0 | name[0] = '\0'; |
1540 | 0 | for(; RTA_OK(rtap, rtl); rtap = RTA_NEXT(rtap, rtl)) { |
1541 | 0 | switch(rtap->rta_type) { |
1542 | 0 | case IFA_ADDRESS: |
1543 | 0 | if((*(int *)RTA_DATA(rtap)) == htons(0xfe80)) { |
1544 | 0 | LM_DBG("Link Local Address, ignoring ...\n"); |
1545 | 0 | is_link_local = 1; |
1546 | 0 | break; |
1547 | 0 | } |
1548 | 0 | inet_ntop(families[i], RTA_DATA(rtap), entry->addr, |
1549 | 0 | MAX_IF_LEN); |
1550 | 0 | LM_DBG("iface <IFA_ADDRESS> addr is %s\n", |
1551 | 0 | entry->addr); |
1552 | 0 | break; |
1553 | 0 | case IFA_LOCAL: |
1554 | 0 | if((*(int *)RTA_DATA(rtap)) == htons(0xfe80)) { |
1555 | 0 | LM_DBG("Link Local Address, ignoring ...\n"); |
1556 | 0 | is_link_local = 1; |
1557 | 0 | } |
1558 | 0 | inet_ntop(families[i], RTA_DATA(rtap), entry->addr, |
1559 | 0 | MAX_IF_LEN); |
1560 | 0 | LM_DBG("iface <IFA_LOCAL> addr is %s\n", entry->addr); |
1561 | 0 | break; |
1562 | 0 | case IFA_LABEL: |
1563 | 0 | LM_DBG("iface name is %s\n", (char *)RTA_DATA(rtap)); |
1564 | 0 | strncpy(name, (char *)RTA_DATA(rtap), MAX_IF_LEN - 1); |
1565 | 0 | name[MAX_IF_LEN - 1] = '\0'; |
1566 | 0 | break; |
1567 | 0 | case IFA_BROADCAST: |
1568 | 0 | case IFA_ANYCAST: |
1569 | 0 | case IFA_UNSPEC: |
1570 | 0 | case IFA_CACHEINFO: |
1571 | 0 | default: |
1572 | 0 | break; |
1573 | 0 | } |
1574 | 0 | } |
1575 | 0 | if(is_link_local) { |
1576 | 0 | if(sr_bind_ipv6_link_local == 0) { |
1577 | | /* skip - link local addresses are not bindable without scope */ |
1578 | 0 | pkg_free(entry); |
1579 | 0 | continue; |
1580 | 0 | } |
1581 | 0 | } |
1582 | | |
1583 | 0 | if(strlen(ifaces[index].name) == 0 && strlen(name) > 0) { |
1584 | 0 | memcpy(ifaces[index].name, name, MAX_IF_LEN - 1); |
1585 | 0 | ifaces[index].name[MAX_IF_LEN - 1] = '\0'; |
1586 | 0 | } |
1587 | |
|
1588 | 0 | ifaces[index].index = index; |
1589 | |
|
1590 | 0 | if(ifaces[index].addresses == 0) |
1591 | 0 | ifaces[index].addresses = entry; |
1592 | 0 | else { |
1593 | 0 | for(tmp = ifaces[index].addresses; tmp->next; |
1594 | 0 | tmp = tmp->next) /*empty*/ |
1595 | 0 | ; |
1596 | 0 | tmp->next = entry; |
1597 | 0 | } |
1598 | 0 | } |
1599 | 0 | } |
1600 | 0 | if(nl_sock > 0) |
1601 | 0 | close(nl_sock); |
1602 | | /* the socket should be closed so we can bind again */ |
1603 | 0 | for(i = 0; i < sizeof(families) / sizeof(int); i++) { |
1604 | | /* get device flags */ |
1605 | 0 | get_flags(families[i]); /* AF_INET or AF_INET6 */ |
1606 | 0 | } |
1607 | |
|
1608 | 0 | return 0; |
1609 | 0 | error: |
1610 | 0 | if(nl_sock >= 0) |
1611 | 0 | close(nl_sock); |
1612 | 0 | return -1; |
1613 | 0 | } |
1614 | | /* add all family type addresses of interface if_name to the socket_info array |
1615 | | * if family ==0, uses all families |
1616 | | * if if_name==0, adds all addresses on all interfaces |
1617 | | * uses RTNETLINK sockets to get addresses on the present interface on LINUX |
1618 | | * return: -1 on error, 0 on success |
1619 | | */ |
1620 | | int add_interfaces_via_netlink(char *if_name, int family, unsigned short port, |
1621 | | unsigned short proto, struct addr_info **ai_l) |
1622 | 0 | { |
1623 | 0 | int i; |
1624 | 0 | struct idx *tmp; |
1625 | 0 | enum si_flags flags; |
1626 | |
|
1627 | 0 | if(ifaces == NULL && (build_iface_list() != 0)) { |
1628 | 0 | LM_ERR("Could not get network interface list\n"); |
1629 | 0 | return -1; |
1630 | 0 | } |
1631 | | |
1632 | 0 | flags = SI_NONE; |
1633 | 0 | for(i = 0; i < MAX_IFACE_NO; ++i) { |
1634 | 0 | if(ifaces[i].addresses == NULL) |
1635 | 0 | continue; /* not present/configured */ |
1636 | 0 | if((if_name == 0) |
1637 | 0 | || (strncmp(if_name, ifaces[i].name, strlen(ifaces[i].name)) |
1638 | 0 | == 0)) { |
1639 | | |
1640 | | /* check if iface is up */ |
1641 | | //if(! (ifaces[i].flags & IFF_UP) ) continue; |
1642 | |
|
1643 | 0 | for(tmp = ifaces[i].addresses; tmp; tmp = tmp->next) { |
1644 | 0 | LM_DBG("in add_iface_via_netlink Name %s Address %s\n", |
1645 | 0 | ifaces[i].name, tmp->addr); |
1646 | | /* match family */ |
1647 | 0 | if(family && family == tmp->family) { |
1648 | | /* check if loopback */ |
1649 | 0 | if(ifaces[i].flags & IFF_LOOPBACK) { |
1650 | 0 | LM_DBG("INTERFACE %s is loopback", ifaces[i].name); |
1651 | 0 | flags |= SI_IS_LO; |
1652 | 0 | } |
1653 | | /* save the info */ |
1654 | 0 | if(new_addr_info2list(tmp->addr, flags, ai_l) != 0) { |
1655 | 0 | LM_ERR("new_addr_info2list failed\n"); |
1656 | 0 | goto error; |
1657 | 0 | } |
1658 | 0 | } |
1659 | 0 | } |
1660 | 0 | } |
1661 | 0 | } |
1662 | 0 | return 0; |
1663 | 0 | error: |
1664 | 0 | return -1; |
1665 | 0 | } |
1666 | | #endif /* __OS_linux */ |
1667 | | |
1668 | | /* add all family type addresses of interface if_name to the socket_info array |
1669 | | * if family ==0, uses all families |
1670 | | * if if_name==0, adds all addresses on all interfaces |
1671 | | * return: -1 on error, 0 on success |
1672 | | */ |
1673 | | int add_interfaces(char *if_name, int family, unsigned short port, |
1674 | | unsigned short proto, struct addr_info **ai_l) |
1675 | 0 | { |
1676 | 0 | char *tmp; |
1677 | 0 | struct ip_addr addr; |
1678 | 0 | int ret = -1; |
1679 | 0 | enum si_flags flags; |
1680 | 0 | struct ifaddrs *ifap, *ifa; |
1681 | |
|
1682 | 0 | if(getifaddrs(&ifap) != 0) { |
1683 | 0 | LM_ERR("getifaddrs failed\n"); |
1684 | 0 | return -1; |
1685 | 0 | } |
1686 | | |
1687 | 0 | for(ifa = ifap; ifa; ifa = ifa->ifa_next) { |
1688 | | /* skip if no IP addr associated with the interface */ |
1689 | 0 | if(ifa->ifa_addr == 0) |
1690 | 0 | continue; |
1691 | 0 | #ifdef AF_PACKET |
1692 | | /* skip AF_PACKET addr family since it is of no use later on */ |
1693 | 0 | if(ifa->ifa_addr->sa_family == AF_PACKET) |
1694 | 0 | continue; |
1695 | 0 | #endif |
1696 | 0 | if(if_name && strcmp(if_name, ifa->ifa_name)) |
1697 | 0 | continue; |
1698 | 0 | if(family && family != ifa->ifa_addr->sa_family) |
1699 | 0 | continue; |
1700 | 0 | sockaddr2ip_addr(&addr, (struct sockaddr *)ifa->ifa_addr); |
1701 | 0 | tmp = ip_addr2a(&addr); |
1702 | 0 | if(ifa->ifa_flags & IFF_LOOPBACK) |
1703 | 0 | flags = SI_IS_LO; |
1704 | 0 | else |
1705 | 0 | flags = SI_NONE; |
1706 | 0 | if(new_addr_info2list(tmp, flags, ai_l) != 0) { |
1707 | 0 | LM_ERR("new_addr_info2list failed\n"); |
1708 | 0 | ret = -1; |
1709 | 0 | break; |
1710 | 0 | } |
1711 | 0 | LM_DBG("If: %8s Fam: %8x Flg: %16lx Adr: %s\n", ifa->ifa_name, |
1712 | 0 | ifa->ifa_addr->sa_family, (unsigned long)ifa->ifa_flags, tmp); |
1713 | |
|
1714 | 0 | ret = 0; |
1715 | 0 | } |
1716 | 0 | freeifaddrs(ifap); |
1717 | 0 | return ret; |
1718 | 0 | } |
1719 | | |
1720 | | |
1721 | | /* internal helper function: resolve host names and add aliases |
1722 | | * name is a value result parameter: it should contain the hostname that |
1723 | | * will be used to fill all the other members, including name itself |
1724 | | * in some situation (name->s should be a 0 terminated pkg_malloc'ed string) |
1725 | | * return 0 on success and -1 on error */ |
1726 | | static int fix_hostname(str *name, struct ip_addr *address, str *address_str, |
1727 | | enum si_flags *flags, int *type_flags, struct socket_info *s) |
1728 | 0 | { |
1729 | 0 | struct hostent *he; |
1730 | 0 | char *tmp; |
1731 | 0 | char **h; |
1732 | | |
1733 | | /* get "official hostnames", all the aliases etc. */ |
1734 | 0 | he = resolvehost(name->s); |
1735 | 0 | if(he == 0) { |
1736 | 0 | LM_ERR("could not resolve %s\n", name->s); |
1737 | 0 | goto error; |
1738 | 0 | } |
1739 | | /* check if we got the official name */ |
1740 | 0 | if(strcasecmp(he->h_name, name->s) != 0) { |
1741 | 0 | if(sr_auto_aliases |
1742 | 0 | && add_alias(name->s, name->len, s->port_no, s->proto) < 0) { |
1743 | 0 | LM_ERR("add_alias failed\n"); |
1744 | 0 | } |
1745 | | /* change the official name */ |
1746 | 0 | pkg_free(name->s); |
1747 | 0 | name->s = (char *)pkg_malloc(strlen(he->h_name) + 1); |
1748 | 0 | if(name->s == 0) { |
1749 | 0 | PKG_MEM_ERROR; |
1750 | 0 | goto error; |
1751 | 0 | } |
1752 | 0 | name->len = strlen(he->h_name); |
1753 | 0 | strncpy(name->s, he->h_name, name->len + 1); |
1754 | 0 | } |
1755 | | /* add the aliases*/ |
1756 | 0 | for(h = he->h_aliases; sr_auto_aliases && h && *h; h++) |
1757 | 0 | if(add_alias(*h, strlen(*h), s->port_no, s->proto) < 0) { |
1758 | 0 | LM_ERR("add_alias failed\n"); |
1759 | 0 | } |
1760 | 0 | hostent2ip_addr(address, he, 0); /*convert to ip_addr format*/ |
1761 | 0 | if(type_flags) { |
1762 | 0 | *type_flags |= (address->af == AF_INET) ? SOCKET_T_IPV4 : SOCKET_T_IPV6; |
1763 | 0 | } |
1764 | 0 | if((tmp = ip_addr2a(address)) == 0) |
1765 | 0 | goto error; |
1766 | 0 | address_str->s = pkg_malloc(strlen(tmp) + 1); |
1767 | 0 | if(address_str->s == 0) { |
1768 | 0 | PKG_MEM_ERROR; |
1769 | 0 | goto error; |
1770 | 0 | } |
1771 | 0 | address_str->len = strlen(tmp); |
1772 | 0 | strncpy(address_str->s, tmp, address_str->len + 1); |
1773 | | /* set is_ip (1 if name is an ip address, 0 otherwise) */ |
1774 | 0 | if(sr_auto_aliases && (address_str->len == name->len) |
1775 | 0 | && (strncasecmp(address_str->s, name->s, address_str->len) == 0)) { |
1776 | 0 | *flags |= SI_IS_IP; |
1777 | | /* do rev. DNS on it (for aliases)*/ |
1778 | 0 | he = rev_resolvehost(address); |
1779 | 0 | if(he == 0) { |
1780 | 0 | LM_WARN("could not rev. resolve %s\n", name->s); |
1781 | 0 | } else { |
1782 | | /* add the aliases*/ |
1783 | 0 | if(add_alias(he->h_name, strlen(he->h_name), s->port_no, s->proto) |
1784 | 0 | < 0) { |
1785 | 0 | LM_ERR("add_alias failed\n"); |
1786 | 0 | } |
1787 | 0 | for(h = he->h_aliases; h && *h; h++) |
1788 | 0 | if(add_alias(*h, strlen(*h), s->port_no, s->proto) < 0) { |
1789 | 0 | LM_ERR("add_alias failed\n"); |
1790 | 0 | } |
1791 | 0 | } |
1792 | 0 | } |
1793 | |
|
1794 | 0 | #ifdef USE_MCAST |
1795 | | /* Check if it is a multicast address and |
1796 | | * set the flag if so |
1797 | | */ |
1798 | 0 | if(is_mcast(address)) { |
1799 | 0 | *flags |= SI_IS_MCAST; |
1800 | 0 | } |
1801 | 0 | #endif /* USE_MCAST */ |
1802 | | |
1803 | | /* check if INADDR_ANY */ |
1804 | 0 | if(ip_addr_any(address)) |
1805 | 0 | *flags |= SI_IS_ANY; |
1806 | 0 | else if(ip_addr_loopback(address)) /* check for loopback */ |
1807 | 0 | *flags |= SI_IS_LO; |
1808 | |
|
1809 | 0 | return 0; |
1810 | 0 | error: |
1811 | 0 | return -1; |
1812 | 0 | } |
1813 | | |
1814 | | |
1815 | | /* append new elements to a socket_info list after "list" |
1816 | | * each element is created from addr_info_lst + port, protocol and flags |
1817 | | * return 0 on success, -1 on error |
1818 | | */ |
1819 | | static int addr_info_to_si_lst(struct addr_info *ai_lst, unsigned short port, |
1820 | | char proto, char useproto, char *usename, unsigned short useport, |
1821 | | char *sockname, enum si_flags flags, struct socket_info **list) |
1822 | 0 | { |
1823 | 0 | struct addr_info *ail; |
1824 | |
|
1825 | 0 | for(ail = ai_lst; ail; ail = ail->next) { |
1826 | 0 | if(new_sock2list(ail->name.s, 0, port, proto, useproto, usename, |
1827 | 0 | useport, sockname, ail->flags | flags, list) |
1828 | 0 | == 0) |
1829 | 0 | return -1; |
1830 | 0 | } |
1831 | 0 | return 0; |
1832 | 0 | } |
1833 | | |
1834 | | |
1835 | | /* insert new elements to a socket_info list after "el", |
1836 | | * each element is created from addr_info_lst + port, * protocol and flags |
1837 | | * return 0 on success, -1 on error |
1838 | | */ |
1839 | | static int addr_info_to_si_lst_after(struct addr_info *ai_lst, |
1840 | | unsigned short port, char proto, char useproto, char *usename, |
1841 | | unsigned short useport, char *sockname, enum si_flags flags, |
1842 | | struct socket_info *el) |
1843 | 0 | { |
1844 | 0 | struct addr_info *ail; |
1845 | 0 | struct socket_info *new_si; |
1846 | |
|
1847 | 0 | for(ail = ai_lst; ail; ail = ail->next) { |
1848 | 0 | if((new_si = new_sock2list_after(ail->name.s, 0, port, proto, useproto, |
1849 | 0 | usename, useport, sockname, ail->flags | flags, el)) |
1850 | 0 | == 0) |
1851 | 0 | return -1; |
1852 | 0 | el = new_si; |
1853 | 0 | } |
1854 | 0 | return 0; |
1855 | 0 | } |
1856 | | |
1857 | | |
1858 | | /* fixes a socket list => resolve addresses, |
1859 | | * interface names, fills missing members, remove duplicates |
1860 | | * fills type_flags if not null with SOCKET_T_IPV4 and/or SOCKET_T_IPV6*/ |
1861 | | static int fix_socket_list(struct socket_info **list, int *type_flags) |
1862 | 0 | { |
1863 | 0 | struct socket_info *si; |
1864 | 0 | struct socket_info *new_si; |
1865 | 0 | struct socket_info *l; |
1866 | 0 | struct socket_info *next; |
1867 | 0 | struct socket_info *next_si; |
1868 | 0 | struct socket_info *del_si; |
1869 | 0 | struct socket_info *keep_si; |
1870 | 0 | char *tmp; |
1871 | 0 | int len; |
1872 | 0 | struct addr_info *ai_lst; |
1873 | 0 | struct addr_info *ail; |
1874 | 0 | struct addr_info *tmp_ail; |
1875 | 0 | struct addr_info *tmp_ail_next; |
1876 | 0 | struct addr_info *ail_next; |
1877 | |
|
1878 | 0 | if(type_flags) |
1879 | 0 | *type_flags = 0; |
1880 | | /* try to change all the interface names into addresses |
1881 | | * --ugly hack */ |
1882 | 0 | for(si = *list; si;) { |
1883 | 0 | next = si->next; |
1884 | 0 | ai_lst = 0; |
1885 | 0 | if(add_interfaces(si->name.s, auto_bind_ipv6 ? 0 : AF_INET, si->port_no, |
1886 | 0 | si->proto, &ai_lst) |
1887 | 0 | != -1) { |
1888 | 0 | if(si->flags & SI_IS_MHOMED) { |
1889 | 0 | if((new_si = new_sock2list_after(ai_lst->name.s, 0, si->port_no, |
1890 | 0 | si->proto, si->useinfo.proto, si->useinfo.name.s, |
1891 | 0 | si->useinfo.port_no, si->sockname.s, |
1892 | 0 | ai_lst->flags | si->flags, si)) |
1893 | 0 | == 0) |
1894 | 0 | break; |
1895 | 0 | ail = ai_lst; |
1896 | 0 | ai_lst = ai_lst->next; |
1897 | 0 | free_addr_info(ail); /* free the first elem. */ |
1898 | 0 | if(ai_lst) { |
1899 | 0 | ai_lst->prev = 0; |
1900 | | /* find the end */ |
1901 | 0 | for(ail = ai_lst; ail->next; ail = ail->next) |
1902 | 0 | ; |
1903 | | /* add the mh list after the last position in ai_lst */ |
1904 | 0 | addr_info_list_ins_lst(si->addr_info_lst, ail); |
1905 | 0 | new_si->addr_info_lst = ai_lst; |
1906 | 0 | si->addr_info_lst = 0; /* detached and moved to new_si */ |
1907 | 0 | ail = ail->next; /* ail== old si->addr_info_lst */ |
1908 | 0 | } else { |
1909 | 0 | ail = si->addr_info_lst; |
1910 | 0 | new_si->addr_info_lst = ail; |
1911 | 0 | si->addr_info_lst = 0; /* detached and moved to new_si */ |
1912 | 0 | } |
1913 | 0 | } else { |
1914 | | /* add all addr. as separate interfaces */ |
1915 | 0 | if(addr_info_to_si_lst_after(ai_lst, si->port_no, si->proto, |
1916 | 0 | si->useinfo.proto, si->useinfo.name.s, |
1917 | 0 | si->useinfo.port_no, si->sockname.s, si->flags, si) |
1918 | 0 | != 0) |
1919 | 0 | goto error; |
1920 | | /* ai_lst not needed anymore */ |
1921 | 0 | free_addr_info_lst(&ai_lst); |
1922 | 0 | ail = 0; |
1923 | 0 | new_si = 0; |
1924 | 0 | } |
1925 | | /* success => remove current entry (shift the entire array)*/ |
1926 | 0 | sock_listrm(list, si); |
1927 | 0 | free_sock_info(si); |
1928 | 0 | } else { |
1929 | 0 | new_si = si; |
1930 | 0 | ail = si->addr_info_lst; |
1931 | 0 | } |
1932 | | |
1933 | 0 | if(ail) { |
1934 | 0 | if(new_si && (new_si->flags & SI_IS_MHOMED)) { |
1935 | 0 | ai_lst = 0; |
1936 | 0 | for(; ail;) { |
1937 | 0 | ail_next = ail->next; |
1938 | 0 | if(add_interfaces(ail->name.s, AF_INET, new_si->port_no, |
1939 | 0 | new_si->proto, &ai_lst) |
1940 | 0 | != -1) { |
1941 | | /* add the resolved list after the current position */ |
1942 | 0 | addr_info_list_ins_lst(ai_lst, ail); |
1943 | | /* success, remove the current entity */ |
1944 | 0 | addr_info_listrm(&new_si->addr_info_lst, ail); |
1945 | 0 | free_addr_info(ail); |
1946 | 0 | ai_lst = 0; |
1947 | 0 | } |
1948 | 0 | ail = ail_next; |
1949 | 0 | } |
1950 | 0 | } |
1951 | 0 | } |
1952 | 0 | si = next; |
1953 | 0 | } |
1954 | | /* get ips & fill the port numbers*/ |
1955 | | #ifdef EXTRA_DEBUG |
1956 | | LM_DBG("Listening on\n"); |
1957 | | #endif |
1958 | 0 | for(si = *list; si; si = si->next) { |
1959 | | /* fix port number, port_no should be !=0 here */ |
1960 | 0 | if(si->port_no == 0) { |
1961 | 0 | #ifdef USE_TLS |
1962 | 0 | si->port_no = (si->proto == PROTO_TLS) ? tls_port_no : port_no; |
1963 | | #else |
1964 | | si->port_no = port_no; |
1965 | | #endif |
1966 | 0 | } |
1967 | 0 | tmp = int2str(si->port_no, &len); |
1968 | 0 | if(len >= MAX_PORT_LEN) { |
1969 | 0 | LM_ERR("bad port number: %d\n", si->port_no); |
1970 | 0 | goto error; |
1971 | 0 | } |
1972 | 0 | si->port_no_str.s = (char *)pkg_malloc(len + 1); |
1973 | 0 | if(si->port_no_str.s == 0) { |
1974 | 0 | PKG_MEM_ERROR; |
1975 | 0 | goto error; |
1976 | 0 | } |
1977 | 0 | strncpy(si->port_no_str.s, tmp, len + 1); |
1978 | 0 | si->port_no_str.len = len; |
1979 | |
|
1980 | 0 | if(fix_hostname(&si->name, &si->address, &si->address_str, &si->flags, |
1981 | 0 | type_flags, si) |
1982 | 0 | != 0) |
1983 | 0 | goto error; |
1984 | | /* fix hostnames in mh addresses */ |
1985 | 0 | for(ail = si->addr_info_lst; ail; ail = ail->next) { |
1986 | 0 | if(fix_hostname(&ail->name, &ail->address, &ail->address_str, |
1987 | 0 | &ail->flags, type_flags, si) |
1988 | 0 | != 0) |
1989 | 0 | goto error; |
1990 | 0 | } |
1991 | | |
1992 | 0 | if(fix_sock_str(si) < 0) |
1993 | 0 | goto error; |
1994 | |
|
1995 | | #ifdef EXTRA_DEBUG |
1996 | | printf(" %.*s [%s]:%s%s\n", si->name.len, si->name.s, |
1997 | | si->address_str.s, si->port_no_str.s, |
1998 | | si->flags & SI_IS_MCAST ? " mcast" : ""); |
1999 | | #endif |
2000 | 0 | } |
2001 | | /* removing duplicate addresses*/ |
2002 | 0 | for(si = *list; si;) { |
2003 | 0 | next_si = si->next; |
2004 | 0 | for(l = si->next; l;) { |
2005 | 0 | next = l->next; |
2006 | 0 | if((si->port_no == l->port_no) && (si->address.af == l->address.af) |
2007 | 0 | && (memcmp(si->address.u.addr, l->address.u.addr, |
2008 | 0 | si->address.len) |
2009 | 0 | == 0)) { |
2010 | | /* remove the socket with no extra addresses., |
2011 | | * if both of them have extra addresses, remove one of them |
2012 | | * and merge the extra addresses into the other */ |
2013 | 0 | if(l->addr_info_lst == 0) { |
2014 | 0 | del_si = l; |
2015 | 0 | keep_si = si; |
2016 | 0 | } else if(si->addr_info_lst == 0) { |
2017 | 0 | del_si = si; |
2018 | 0 | keep_si = l; |
2019 | 0 | } else { |
2020 | | /* move l->addr_info_lst to si->addr_info_lst */ |
2021 | | /* find last elem */ |
2022 | 0 | for(ail = si->addr_info_lst; ail->next; ail = ail->next) |
2023 | 0 | ; |
2024 | | /* add the l list after the last position in si lst */ |
2025 | 0 | addr_info_list_ins_lst(l->addr_info_lst, ail); |
2026 | 0 | l->addr_info_lst = 0; /* detached */ |
2027 | 0 | del_si = l; /* l will be removed */ |
2028 | 0 | keep_si = l; |
2029 | 0 | } |
2030 | | #ifdef EXTRA_DEBUG |
2031 | | printf("removing duplicate %s [%s] == %s [%s]\n", |
2032 | | keep_si->name.s, keep_si->address_str.s, del_si->name.s, |
2033 | | del_si->address_str.s); |
2034 | | #endif |
2035 | | /* add the name to the alias list*/ |
2036 | 0 | if((!(del_si->flags & SI_IS_IP)) |
2037 | 0 | && ((del_si->name.len != keep_si->name.len) |
2038 | 0 | || (strncmp(del_si->name.s, keep_si->name.s, |
2039 | 0 | del_si->name.len) |
2040 | 0 | != 0))) |
2041 | 0 | add_alias(del_si->name.s, del_si->name.len, l->port_no, |
2042 | 0 | l->proto); |
2043 | | /* make sure next_si doesn't point to del_si */ |
2044 | 0 | if(del_si == next_si) |
2045 | 0 | next_si = next_si->next; |
2046 | | /* remove del_si*/ |
2047 | 0 | sock_listrm(list, del_si); |
2048 | 0 | free_sock_info(del_si); |
2049 | 0 | } |
2050 | 0 | l = next; |
2051 | 0 | } |
2052 | 0 | si = next_si; |
2053 | 0 | } |
2054 | | /* check for duplicates in extra_addresses */ |
2055 | 0 | for(si = *list; si; si = si->next) { |
2056 | | /* check for & remove internal duplicates: */ |
2057 | 0 | for(ail = si->addr_info_lst; ail;) { |
2058 | 0 | ail_next = ail->next; |
2059 | | /* 1. check if the extra addresses contain a duplicate for the |
2060 | | * main one */ |
2061 | 0 | if((ail->address.af == si->address.af) |
2062 | 0 | && (memcmp(ail->address.u.addr, si->address.u.addr, |
2063 | 0 | ail->address.len) |
2064 | 0 | == 0)) { |
2065 | | /* add the name to the alias list*/ |
2066 | 0 | if((!(ail->flags & SI_IS_IP)) |
2067 | 0 | && ((ail->name.len != si->name.len) |
2068 | 0 | || (strncmp(ail->name.s, si->name.s, |
2069 | 0 | ail->name.len) |
2070 | 0 | != 0))) |
2071 | 0 | add_alias( |
2072 | 0 | ail->name.s, ail->name.len, si->port_no, si->proto); |
2073 | | /* remove ail*/ |
2074 | 0 | addr_info_listrm(&si->addr_info_lst, ail); |
2075 | 0 | free_addr_info(ail); |
2076 | 0 | ail = ail_next; |
2077 | 0 | continue; |
2078 | 0 | } |
2079 | | /* 2. check if the extra addresses contain a duplicate for |
2080 | | * other addresses in the same list */ |
2081 | 0 | for(tmp_ail = ail->next; tmp_ail;) { |
2082 | 0 | tmp_ail_next = tmp_ail->next; |
2083 | 0 | if((ail->address.af == tmp_ail->address.af) |
2084 | 0 | && (memcmp(ail->address.u.addr, tmp_ail->address.u.addr, |
2085 | 0 | ail->address.len) |
2086 | 0 | == 0)) { |
2087 | | /* add the name to the alias list*/ |
2088 | 0 | if((!(tmp_ail->flags & SI_IS_IP)) |
2089 | 0 | && ((ail->name.len != tmp_ail->name.len) |
2090 | 0 | || (strncmp(ail->name.s, tmp_ail->name.s, |
2091 | 0 | tmp_ail->name.len) |
2092 | 0 | != 0))) |
2093 | 0 | add_alias(tmp_ail->name.s, tmp_ail->name.len, |
2094 | 0 | si->port_no, si->proto); |
2095 | | /* remove tmp_ail*/ |
2096 | 0 | addr_info_listrm(&si->addr_info_lst, tmp_ail); |
2097 | 0 | if(ail_next == tmp_ail) { |
2098 | 0 | ail_next = tmp_ail_next; |
2099 | 0 | } |
2100 | 0 | free_addr_info(tmp_ail); |
2101 | 0 | } |
2102 | 0 | tmp_ail = tmp_ail_next; |
2103 | 0 | } |
2104 | 0 | ail = ail_next; |
2105 | 0 | } |
2106 | | /* check for duplicates between extra addresses (e.g. sctp MH) |
2107 | | * and other main addresses, on conflict remove the corresponding |
2108 | | * extra addresses (another possible solution would be to join |
2109 | | * the 2 si entries into one). */ |
2110 | 0 | for(ail = si->addr_info_lst; ail;) { |
2111 | 0 | ail_next = ail->next; |
2112 | 0 | for(l = *list; l; l = l->next) { |
2113 | 0 | if(l == si) |
2114 | 0 | continue; |
2115 | 0 | if(si->port_no == l->port_no) { |
2116 | 0 | if((ail->address.af == l->address.af) |
2117 | 0 | && (memcmp(ail->address.u.addr, l->address.u.addr, |
2118 | 0 | ail->address.len) |
2119 | 0 | == 0)) { |
2120 | | /* add the name to the alias list*/ |
2121 | 0 | if((!(ail->flags & SI_IS_IP)) |
2122 | 0 | && ((ail->name.len != l->name.len) |
2123 | 0 | || (strncmp(ail->name.s, l->name.s, |
2124 | 0 | l->name.len) |
2125 | 0 | != 0))) |
2126 | 0 | add_alias(ail->name.s, ail->name.len, l->port_no, |
2127 | 0 | l->proto); |
2128 | | /* remove ail*/ |
2129 | 0 | addr_info_listrm(&si->addr_info_lst, ail); |
2130 | 0 | free_addr_info(ail); |
2131 | 0 | break; |
2132 | 0 | } |
2133 | | /* check for duplicates with other extra addresses |
2134 | | * lists */ |
2135 | 0 | for(tmp_ail = l->addr_info_lst; tmp_ail;) { |
2136 | 0 | tmp_ail_next = tmp_ail->next; |
2137 | 0 | if((ail->address.af == tmp_ail->address.af) |
2138 | 0 | && (memcmp(ail->address.u.addr, |
2139 | 0 | tmp_ail->address.u.addr, |
2140 | 0 | ail->address.len) |
2141 | 0 | == 0)) { |
2142 | | /* add the name to the alias list*/ |
2143 | 0 | if((!(tmp_ail->flags & SI_IS_IP)) |
2144 | 0 | && ((ail->name.len != tmp_ail->name.len) |
2145 | 0 | || (strncmp(ail->name.s, |
2146 | 0 | tmp_ail->name.s, |
2147 | 0 | tmp_ail->name.len) |
2148 | 0 | != 0))) |
2149 | 0 | add_alias(tmp_ail->name.s, tmp_ail->name.len, |
2150 | 0 | l->port_no, l->proto); |
2151 | | /* remove tmp_ail*/ |
2152 | 0 | addr_info_listrm(&l->addr_info_lst, tmp_ail); |
2153 | 0 | free_addr_info(tmp_ail); |
2154 | 0 | } |
2155 | 0 | tmp_ail = tmp_ail_next; |
2156 | 0 | } |
2157 | 0 | } |
2158 | 0 | } |
2159 | 0 | ail = ail_next; |
2160 | 0 | } |
2161 | 0 | } |
2162 | |
|
2163 | 0 | #ifdef USE_MCAST |
2164 | | /* Remove invalid multicast entries */ |
2165 | 0 | si = *list; |
2166 | 0 | while(si) { |
2167 | 0 | if((si->proto == PROTO_TCP) |
2168 | 0 | #ifdef USE_TLS |
2169 | 0 | || (si->proto == PROTO_TLS) |
2170 | 0 | #endif /* USE_TLS */ |
2171 | 0 | #ifdef USE_SCTP |
2172 | 0 | || (si->proto == PROTO_SCTP) |
2173 | 0 | #endif |
2174 | 0 | ) { |
2175 | 0 | if(si->flags & SI_IS_MCAST) { |
2176 | 0 | LM_WARN("removing entry %s:%s [%s]:%s\n", |
2177 | 0 | get_valid_proto_name(si->proto), si->name.s, |
2178 | 0 | si->address_str.s, si->port_no_str.s); |
2179 | 0 | l = si; |
2180 | 0 | si = si->next; |
2181 | 0 | sock_listrm(list, l); |
2182 | 0 | free_sock_info(l); |
2183 | 0 | } else { |
2184 | 0 | ail = si->addr_info_lst; |
2185 | 0 | while(ail) { |
2186 | 0 | if(ail->flags & SI_IS_MCAST) { |
2187 | 0 | LM_WARN("removing mh entry %s:%s" |
2188 | 0 | " [%s]:%s\n", |
2189 | 0 | get_valid_proto_name(si->proto), ail->name.s, |
2190 | 0 | ail->address_str.s, si->port_no_str.s); |
2191 | 0 | tmp_ail = ail; |
2192 | 0 | ail = ail->next; |
2193 | 0 | addr_info_listrm(&si->addr_info_lst, tmp_ail); |
2194 | 0 | free_addr_info(tmp_ail); |
2195 | 0 | } else { |
2196 | 0 | ail = ail->next; |
2197 | 0 | } |
2198 | 0 | } |
2199 | 0 | si = si->next; |
2200 | 0 | } |
2201 | 0 | } else { |
2202 | 0 | si = si->next; |
2203 | 0 | } |
2204 | 0 | } |
2205 | 0 | #endif /* USE_MCAST */ |
2206 | |
|
2207 | 0 | return 0; |
2208 | 0 | error: |
2209 | 0 | return -1; |
2210 | 0 | } |
2211 | | |
2212 | | int socket_types = 0; |
2213 | | |
2214 | | /* fix all 3 socket lists, fills socket_types if non-null |
2215 | | * return 0 on success, -1 on error */ |
2216 | | int fix_all_socket_lists() |
2217 | 0 | { |
2218 | 0 | struct utsname myname; |
2219 | 0 | int flags; |
2220 | 0 | struct addr_info *ai_lst; |
2221 | |
|
2222 | 0 | ai_lst = 0; |
2223 | |
|
2224 | 0 | if((udp_listen == 0) |
2225 | 0 | #ifdef USE_TCP |
2226 | 0 | && (tcp_listen == 0) |
2227 | 0 | #ifdef USE_TLS |
2228 | 0 | && (tls_listen == 0) |
2229 | 0 | #endif |
2230 | 0 | #endif |
2231 | 0 | #ifdef USE_SCTP |
2232 | 0 | && (sctp_listen == 0) |
2233 | 0 | #endif |
2234 | 0 | ) { |
2235 | | /* get all listening ipv4/ipv6 interfaces */ |
2236 | 0 | if(((add_interfaces(0, AF_INET, 0, PROTO_UDP, &ai_lst) == 0) |
2237 | 0 | #ifdef __OS_linux |
2238 | 0 | && (!auto_bind_ipv6 |
2239 | 0 | || add_interfaces_via_netlink( |
2240 | 0 | 0, AF_INET6, 0, PROTO_UDP, &ai_lst) |
2241 | 0 | == 0) |
2242 | | #else |
2243 | | && (!auto_bind_ipv6 |
2244 | | || add_interfaces(0, AF_INET6, 0, PROTO_UDP, &ai_lst) |
2245 | | == 0) /* add_interface does not work for IPv6 on Linux */ |
2246 | | #endif /* __OS_linux */ |
2247 | 0 | ) |
2248 | 0 | && (addr_info_to_si_lst( |
2249 | 0 | ai_lst, 0, PROTO_UDP, 0, 0, 0, 0, 0, &udp_listen) |
2250 | 0 | == 0)) { |
2251 | 0 | free_addr_info_lst(&ai_lst); |
2252 | 0 | ai_lst = 0; |
2253 | | /* if ok, try to add the others too */ |
2254 | 0 | #ifdef USE_TCP |
2255 | 0 | if(!tcp_disable) { |
2256 | 0 | if(((add_interfaces(0, AF_INET, 0, PROTO_TCP, &ai_lst) != 0) |
2257 | 0 | #ifdef __OS_linux |
2258 | 0 | || (auto_bind_ipv6 |
2259 | 0 | && add_interfaces_via_netlink(0, AF_INET6, 0, |
2260 | 0 | PROTO_TCP, &ai_lst) |
2261 | 0 | != 0) |
2262 | | #else |
2263 | | || (auto_bind_ipv6 |
2264 | | && add_interfaces(0, AF_INET6, 0, PROTO_TCP, |
2265 | | &ai_lst) |
2266 | | != 0) |
2267 | | #endif /* __OS_linux */ |
2268 | 0 | ) |
2269 | 0 | || (addr_info_to_si_lst(ai_lst, 0, PROTO_TCP, 0, 0, 0, |
2270 | 0 | 0, 0, &tcp_listen) |
2271 | 0 | != 0)) |
2272 | 0 | goto error; |
2273 | 0 | free_addr_info_lst(&ai_lst); |
2274 | 0 | ai_lst = 0; |
2275 | 0 | #ifdef USE_TLS |
2276 | 0 | if(!tls_disable) { |
2277 | 0 | if(((add_interfaces(0, AF_INET, 0, PROTO_TLS, &ai_lst) != 0) |
2278 | 0 | #ifdef __OS_linux |
2279 | 0 | || (auto_bind_ipv6 |
2280 | 0 | && add_interfaces_via_netlink(0, |
2281 | 0 | AF_INET6, 0, PROTO_TLS, |
2282 | 0 | &ai_lst) |
2283 | 0 | != 0) |
2284 | | #else |
2285 | | || (auto_bind_ipv6 |
2286 | | && add_interfaces(0, AF_INET6, 0, |
2287 | | PROTO_TLS, &ai_lst) |
2288 | | != 0) |
2289 | | #endif /* __OS_linux */ |
2290 | 0 | ) |
2291 | 0 | || (addr_info_to_si_lst(ai_lst, 0, PROTO_TLS, 0, 0, |
2292 | 0 | 0, 0, 0, &tls_listen) |
2293 | 0 | != 0)) |
2294 | 0 | goto error; |
2295 | 0 | } |
2296 | 0 | free_addr_info_lst(&ai_lst); |
2297 | 0 | ai_lst = 0; |
2298 | 0 | #endif |
2299 | 0 | } |
2300 | 0 | #endif |
2301 | 0 | #ifdef USE_SCTP |
2302 | 0 | if(!sctp_disable) { |
2303 | 0 | if(((add_interfaces(0, AF_INET, 0, PROTO_SCTP, &ai_lst) != 0) |
2304 | 0 | #ifdef __OS_linux |
2305 | 0 | || (auto_bind_ipv6 |
2306 | 0 | && add_interfaces_via_netlink(0, AF_INET6, 0, |
2307 | 0 | PROTO_SCTP, &ai_lst) |
2308 | 0 | != 0) |
2309 | | #else |
2310 | | || (auto_bind_ipv6 |
2311 | | && add_interfaces(0, AF_INET6, 0, PROTO_SCTP, |
2312 | | &ai_lst) |
2313 | | != 0) |
2314 | | #endif /* __OS_linux */ |
2315 | 0 | ) |
2316 | 0 | || (addr_info_to_si_lst(ai_lst, 0, PROTO_SCTP, 0, 0, 0, |
2317 | 0 | 0, 0, &sctp_listen) |
2318 | 0 | != 0)) |
2319 | 0 | goto error; |
2320 | 0 | free_addr_info_lst(&ai_lst); |
2321 | 0 | ai_lst = 0; |
2322 | 0 | } |
2323 | 0 | #endif /* USE_SCTP */ |
2324 | 0 | } else { |
2325 | | /* if error fall back to get hostname */ |
2326 | | /* get our address, only the first one */ |
2327 | 0 | if(uname(&myname) < 0) { |
2328 | 0 | LM_ERR("cannot determine hostname, try -l address\n"); |
2329 | 0 | goto error; |
2330 | 0 | } |
2331 | 0 | if(add_listen_iface(myname.nodename, 0, 0, 0, 0) != 0) { |
2332 | 0 | LM_ERR("add_listen_iface failed \n"); |
2333 | 0 | goto error; |
2334 | 0 | } |
2335 | 0 | } |
2336 | 0 | } |
2337 | 0 | flags = 0; |
2338 | 0 | if(fix_socket_list(&udp_listen, &flags) != 0) { |
2339 | 0 | LM_ERR("fix_socket_list udp failed\n"); |
2340 | 0 | goto error; |
2341 | 0 | } |
2342 | 0 | if(flags) { |
2343 | 0 | socket_types |= flags | SOCKET_T_UDP; |
2344 | 0 | } |
2345 | 0 | #ifdef USE_TCP |
2346 | 0 | flags = 0; |
2347 | 0 | if(!tcp_disable && (fix_socket_list(&tcp_listen, &flags) != 0)) { |
2348 | 0 | LM_ERR("fix_socket_list tcp failed\n"); |
2349 | 0 | goto error; |
2350 | 0 | } |
2351 | 0 | if(flags) { |
2352 | 0 | socket_types |= flags | SOCKET_T_TCP; |
2353 | 0 | } |
2354 | 0 | #ifdef USE_TLS |
2355 | 0 | flags = 0; |
2356 | 0 | if(!tls_disable && (fix_socket_list(&tls_listen, &flags) != 0)) { |
2357 | 0 | LM_ERR("fix_socket_list tls failed\n"); |
2358 | 0 | goto error; |
2359 | 0 | } |
2360 | 0 | if(flags) { |
2361 | 0 | socket_types |= flags | SOCKET_T_TLS; |
2362 | 0 | } |
2363 | 0 | #endif |
2364 | 0 | #endif |
2365 | 0 | #ifdef USE_SCTP |
2366 | 0 | flags = 0; |
2367 | 0 | if(!sctp_disable && (fix_socket_list(&sctp_listen, &flags) != 0)) { |
2368 | 0 | LM_ERR("fix_socket_list sctp failed\n"); |
2369 | 0 | goto error; |
2370 | 0 | } |
2371 | 0 | if(flags) { |
2372 | 0 | socket_types |= flags | SOCKET_T_SCTP; |
2373 | 0 | } |
2374 | 0 | #endif /* USE_SCTP */ |
2375 | 0 | if((udp_listen == 0) |
2376 | 0 | #ifdef USE_TCP |
2377 | 0 | && (tcp_listen == 0) |
2378 | 0 | #ifdef USE_TLS |
2379 | 0 | && (tls_listen == 0) |
2380 | 0 | #endif |
2381 | 0 | #endif |
2382 | 0 | #ifdef USE_SCTP |
2383 | 0 | && (sctp_listen == 0) |
2384 | 0 | #endif |
2385 | 0 | ) { |
2386 | 0 | LM_ERR("no listening sockets\n"); |
2387 | 0 | goto error; |
2388 | 0 | } |
2389 | 0 | return 0; |
2390 | 0 | error: |
2391 | 0 | if(ai_lst) |
2392 | 0 | free_addr_info_lst(&ai_lst); |
2393 | 0 | return -1; |
2394 | 0 | } |
2395 | | |
2396 | | |
2397 | | void print_all_socket_lists() |
2398 | 0 | { |
2399 | 0 | struct socket_info *si; |
2400 | 0 | struct socket_info **list; |
2401 | 0 | struct addr_info *ai; |
2402 | 0 | unsigned short proto; |
2403 | |
|
2404 | 0 | proto = PROTO_UDP; |
2405 | 0 | do { |
2406 | 0 | list = get_sock_info_list(proto); |
2407 | 0 | for(si = list ? *list : 0; si; si = si->next) { |
2408 | 0 | if(si->addr_info_lst) { |
2409 | 0 | printf(" %s: (%s", get_valid_proto_name(proto), |
2410 | 0 | si->address_str.s); |
2411 | 0 | for(ai = si->addr_info_lst; ai; ai = ai->next) { |
2412 | 0 | printf(", %s", ai->address_str.s); |
2413 | 0 | } |
2414 | 0 | printf("):%s%s%s%s\n", si->port_no_str.s, |
2415 | 0 | si->flags & SI_IS_MCAST ? " mcast" : "", |
2416 | 0 | si->flags & SI_IS_MHOMED ? " mhomed" : "", |
2417 | 0 | si->flags & SI_IS_VIRTUAL ? " virtual" : ""); |
2418 | 0 | } else { |
2419 | 0 | printf(" %s: %s", get_valid_proto_name(proto), |
2420 | 0 | si->name.s); |
2421 | 0 | if(!(si->flags & SI_IS_IP)) { |
2422 | 0 | printf(" [%s]", si->address_str.s); |
2423 | 0 | } |
2424 | 0 | printf(":%s%s%s%s", si->port_no_str.s, |
2425 | 0 | si->flags & SI_IS_MCAST ? " mcast" : "", |
2426 | 0 | si->flags & SI_IS_MHOMED ? " mhomed" : "", |
2427 | 0 | si->flags & SI_IS_VIRTUAL ? " virtual" : ""); |
2428 | 0 | if(si->sockname.s) { |
2429 | 0 | printf(" name %s", si->sockname.s); |
2430 | 0 | } |
2431 | 0 | if(si->useinfo.name.s) { |
2432 | 0 | printf(" advertise %s:%s:%d", |
2433 | 0 | get_valid_proto_name(si->useinfo.proto), |
2434 | 0 | si->useinfo.name.s, si->useinfo.port_no); |
2435 | 0 | } |
2436 | 0 | printf("\n"); |
2437 | 0 | } |
2438 | 0 | } |
2439 | 0 | } while((proto = next_proto(proto))); |
2440 | 0 | } |
2441 | | |
2442 | | |
2443 | | void print_aliases() |
2444 | 0 | { |
2445 | 0 | struct host_alias *a; |
2446 | |
|
2447 | 0 | for(a = aliases; a; a = a->next) { |
2448 | 0 | if(a->port) { |
2449 | 0 | printf(" %s: %.*s:%d\n", get_valid_proto_name(a->proto), |
2450 | 0 | a->alias.len, a->alias.s, a->port); |
2451 | 0 | } else { |
2452 | 0 | printf(" %s: %.*s:*\n", get_valid_proto_name(a->proto), |
2453 | 0 | a->alias.len, a->alias.s); |
2454 | 0 | } |
2455 | 0 | } |
2456 | 0 | } |
2457 | | |
2458 | | |
2459 | | void init_proto_order() |
2460 | 0 | { |
2461 | 0 | int r; |
2462 | | |
2463 | | /* fix proto list (remove disabled protocols)*/ |
2464 | 0 | #ifdef USE_TCP |
2465 | 0 | if(tcp_disable) |
2466 | 0 | #endif |
2467 | 0 | for(r = PROTO_NONE; r <= PROTO_LAST; r++) { |
2468 | 0 | if(nxt_proto[r] == PROTO_TCP) |
2469 | 0 | nxt_proto[r] = nxt_proto[PROTO_TCP]; |
2470 | 0 | } |
2471 | 0 | #ifdef USE_TCP |
2472 | 0 | #ifdef USE_TLS |
2473 | 0 | if(tls_disable || tcp_disable) |
2474 | 0 | #endif |
2475 | 0 | #endif |
2476 | 0 | for(r = PROTO_NONE; r <= PROTO_LAST; r++) { |
2477 | 0 | if(nxt_proto[r] == PROTO_TLS) |
2478 | 0 | nxt_proto[r] = nxt_proto[PROTO_TLS]; |
2479 | 0 | } |
2480 | 0 | #ifdef USE_SCTP |
2481 | 0 | if(sctp_disable) |
2482 | 0 | #endif |
2483 | 0 | for(r = PROTO_NONE; r <= PROTO_LAST; r++) { |
2484 | 0 | if(nxt_proto[r] == PROTO_SCTP) |
2485 | 0 | nxt_proto[r] = nxt_proto[PROTO_SCTP]; |
2486 | 0 | } |
2487 | | |
2488 | | /* Deliberately skipping PROTO_WS and PROTO_WSS here as these |
2489 | | are just upgraded TCP and TLS connections */ |
2490 | 0 | } |
2491 | | |
2492 | | |
2493 | | /** |
2494 | | * parse '[proto:]host[:port]' string to a broken down structure |
2495 | | */ |
2496 | | int parse_protohostport(str *ins, sr_phostp_t *r) |
2497 | 0 | { |
2498 | 0 | char *first; /* first ':' occurrence */ |
2499 | 0 | char *second; /* second ':' occurrence */ |
2500 | 0 | char *p; |
2501 | 0 | int bracket; |
2502 | 0 | str tmp = STR_NULL; |
2503 | |
|
2504 | 0 | first = second = 0; |
2505 | 0 | bracket = 0; |
2506 | 0 | memset(r, 0, sizeof(sr_phostp_t)); |
2507 | | |
2508 | | /* find the first 2 ':', ignoring possible ipv6 addresses |
2509 | | * (substrings between []) |
2510 | | */ |
2511 | 0 | for(p = ins->s; p < ins->s + ins->len; p++) { |
2512 | 0 | switch(*p) { |
2513 | 0 | case '[': |
2514 | 0 | bracket++; |
2515 | 0 | if(bracket > 1) |
2516 | 0 | goto error_brackets; |
2517 | 0 | break; |
2518 | 0 | case ']': |
2519 | 0 | bracket--; |
2520 | 0 | if(bracket < 0) |
2521 | 0 | goto error_brackets; |
2522 | 0 | break; |
2523 | 0 | case ':': |
2524 | 0 | if(bracket == 0) { |
2525 | 0 | if(first == 0) |
2526 | 0 | first = p; |
2527 | 0 | else if(second == 0) |
2528 | 0 | second = p; |
2529 | 0 | else |
2530 | 0 | goto error_colons; |
2531 | 0 | } |
2532 | 0 | break; |
2533 | 0 | } |
2534 | 0 | } |
2535 | 0 | if(p == ins->s) |
2536 | 0 | return -1; |
2537 | 0 | if(*(p - 1) == ':') |
2538 | 0 | goto error_colons; |
2539 | | |
2540 | 0 | if(first == 0) { /* no ':' => only host */ |
2541 | 0 | r->host.s = ins->s; |
2542 | 0 | r->host.len = (int)(p - ins->s); |
2543 | 0 | goto end; |
2544 | 0 | } |
2545 | 0 | if(second) { /* 2 ':' found => check if valid */ |
2546 | 0 | if(parse_proto((unsigned char *)ins->s, first - ins->s, &r->proto) < 0) |
2547 | 0 | goto error_proto; |
2548 | 0 | r->sproto.s = ins->s; |
2549 | 0 | r->sproto.len = first - ins->s; |
2550 | |
|
2551 | 0 | tmp.s = second + 1; |
2552 | 0 | tmp.len = (ins->s + ins->len) - tmp.s; |
2553 | |
|
2554 | 0 | if(str2int(&tmp, (unsigned int *)&(r->port)) < 0) |
2555 | 0 | goto error_port; |
2556 | 0 | r->sport = tmp; |
2557 | |
|
2558 | 0 | r->host.s = first + 1; |
2559 | 0 | r->host.len = (int)(second - r->host.s); |
2560 | 0 | goto end; |
2561 | 0 | } |
2562 | | /* only 1 ':' found => it's either proto:host or host:port */ |
2563 | 0 | tmp.s = first + 1; |
2564 | 0 | tmp.len = (ins->s + ins->len) - tmp.s; |
2565 | 0 | if(str2int(&tmp, (unsigned int *)&(r->port)) < 0) { |
2566 | | /* invalid port => it's proto:host */ |
2567 | 0 | if(parse_proto((unsigned char *)ins->s, first - ins->s, &r->proto) < 0) |
2568 | 0 | goto error_proto; |
2569 | 0 | r->sproto.s = ins->s; |
2570 | 0 | r->sproto.len = first - ins->s; |
2571 | 0 | r->host.s = first + 1; |
2572 | 0 | r->host.len = (int)(p - r->host.s); |
2573 | 0 | } else { |
2574 | | /* valid port => it is host:port */ |
2575 | 0 | r->sport = tmp; |
2576 | 0 | r->host.s = ins->s; |
2577 | 0 | r->host.len = (int)(first - r->host.s); |
2578 | 0 | } |
2579 | 0 | end: |
2580 | 0 | return 0; |
2581 | 0 | error_brackets: |
2582 | 0 | LM_ERR("too many brackets in %.*s\n", ins->len, ins->s); |
2583 | 0 | return -1; |
2584 | 0 | error_colons: |
2585 | 0 | LM_ERR("too many colons in %.*s\n", ins->len, ins->s); |
2586 | 0 | return -1; |
2587 | 0 | error_proto: |
2588 | 0 | LM_ERR("bad protocol in %.*s\n", ins->len, ins->s); |
2589 | 0 | return -1; |
2590 | 0 | error_port: |
2591 | 0 | LM_ERR("bad port number in %.*s\n", ins->len, ins->s); |
2592 | 0 | return -1; |
2593 | 0 | } |
2594 | | |
2595 | | /** |
2596 | | * lookup a local socket by '[proto:]host[:port]' string |
2597 | | */ |
2598 | | struct socket_info *lookup_local_socket(str *phostp) |
2599 | 0 | { |
2600 | 0 | sr_phostp_t r; |
2601 | 0 | if(parse_protohostport(phostp, &r) < 0) |
2602 | 0 | return NULL; |
2603 | 0 | return grep_sock_info( |
2604 | 0 | &r.host, (unsigned short)r.port, (unsigned short)r.proto); |
2605 | 0 | } |
2606 | | |
2607 | | struct socket_info *find_sock_info_by_address_family( |
2608 | | int proto, int address_family) |
2609 | 0 | { |
2610 | 0 | struct addr_info *ai = NULL; |
2611 | 0 | int found = 0; |
2612 | 0 | struct socket_info *si = NULL; |
2613 | 0 | struct socket_info **si_list = get_sock_info_list(proto); |
2614 | |
|
2615 | 0 | for(si = si_list ? *si_list : NULL; si; si = si->next) { |
2616 | 0 | if(si->flags & (SI_IS_LO | SI_IS_MCAST)) { |
2617 | 0 | continue; |
2618 | 0 | } |
2619 | | |
2620 | 0 | if(si->address.af == address_family) { |
2621 | 0 | break; |
2622 | 0 | } |
2623 | | |
2624 | 0 | for(ai = si->addr_info_lst; ai; ai = ai->next) { |
2625 | 0 | if(ai->address.af == address_family) { |
2626 | 0 | found = 1; |
2627 | 0 | break; |
2628 | 0 | } |
2629 | 0 | } |
2630 | |
|
2631 | 0 | if(found) { |
2632 | 0 | break; |
2633 | 0 | } |
2634 | 0 | } |
2635 | |
|
2636 | 0 | return si; |
2637 | 0 | } |