Coverage Report

Created: 2026-03-11 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensips/socket_info.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2001-2003 FhG Fokus
3
 *
4
 * This file is part of opensips, a free SIP server.
5
 *
6
 * opensips is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 2 of the License, or
9
 * (at your option) any later version
10
 *
11
 * opensips is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19
 *
20
 *
21
 * This file contains code that initializes and handles ser listen addresses
22
 * lists (struct socket_info). It is used mainly on startup.
23
 *
24
 * History:
25
 * --------
26
 *  2003-10-22  created by andrei
27
 *  2004-10-10  added grep_sock_info (andrei)
28
 *  2004-11-08  added find_si (andrei)
29
 *  2007-01-11  auto_aliases option added (bogdan)
30
 */
31
32
/*!
33
 * \file
34
 * \brief Find & manage listen addresses
35
 */
36
37
38
#include <string.h>
39
#include <errno.h>
40
#include <unistd.h>
41
#include <sys/types.h>
42
#include <sys/socket.h>
43
#include <sys/utsname.h>
44
#include <stdio.h>
45
46
#include <sys/ioctl.h>
47
#include <net/if.h>
48
#ifdef HAVE_SYS_SOCKIO_H
49
#include <sys/sockio.h>
50
#endif
51
52
#include "str.h"
53
#include "globals.h"
54
#include "socket_info.h"
55
#include "dprint.h"
56
#include "mem/mem.h"
57
#include "ut.h"
58
#include "pt_scaling.h"
59
#include "resolve.h"
60
#include "name_alias.h"
61
#include "net/trans.h"
62
63
#ifdef __OS_linux
64
#include <features.h>     /* for GLIBC version testing */
65
#if defined(__GLIBC_PREREQ)
66
#if __GLIBC_PREREQ(2, 4)
67
#include <ifaddrs.h>
68
#define HAVE_IFADDRS
69
#endif
70
#endif
71
#endif
72
73
0
#define MAX_PROC_BUFFER 256
74
75
/* list manip. functions (internal use only) */
76
77
/* list with BOND sockets only - this is pretty static right now */
78
static struct socket_info_full *bond_sockets;
79
80
/* append */
81
#define sock_listadd(head, el) \
82
0
  do{\
83
0
    if (*(head)==0) *(head)=(el); \
84
0
    else{ \
85
0
      for((el)->next=*(head); (el)->next->next;\
86
0
          (el)->next=(el)->next->next); \
87
0
      (el)->next->next=(el); \
88
0
      (el)->prev=(el)->next; \
89
0
      (el)->next=0; \
90
0
    }\
91
0
  }while(0)
92
93
94
/* insert after "after" */
95
#define sock_listins(el, after) \
96
  do{ \
97
    if ((after)){\
98
      (el)->next=(after)->next; \
99
      if ((after)->next) (after)->next->prev=(el); \
100
      (after)->next=(el); \
101
      (el)->prev=(after); \
102
    }else{ /* after==0 = list head */ \
103
      (after)=(el); \
104
      (el)->next=(el)->prev=0; \
105
    }\
106
  }while(0)
107
108
109
#define sock_listrm(head, el) \
110
0
  do {\
111
0
    if (*(head)==(el)) *(head)=(el)->next; \
112
0
    if ((el)->next) (el)->next->prev=(el)->prev; \
113
0
    if ((el)->prev) (el)->prev->next=(el)->next; \
114
0
  }while(0)
115
116
117
/* another helper function, it just creates a socket_info struct */
118
struct socket_info_full* new_sock_info(struct socket_id *sid, str *orig_name)
119
0
{
120
0
  struct socket_info_full *sif;
121
0
  struct socket_info *si;
122
123
0
  sif=(struct socket_info_full*) pkg_malloc(sizeof(*sif));
124
0
  if (sif==NULL) goto error;
125
0
  memset(sif, 0, sizeof(*sif));
126
0
  si = &sif->socket_info;
127
0
  si->socket=-1;
128
0
  si->last_real_ports = &sif->last_real_ports;
129
130
0
  if (sid->name) {
131
0
    si->name.len=strlen(sid->name);
132
0
    si->name.s=(char*)pkg_malloc(si->name.len+1); /* include \0 */
133
0
    if (si->name.s==0) goto error;
134
0
    memcpy(si->name.s, sid->name, si->name.len+1);
135
0
  }
136
137
0
  if (orig_name && orig_name->s && orig_name->len) {
138
0
    si->orig_name.s = pkg_malloc(orig_name->len + 1);
139
0
    if (si->orig_name.s == 0) {
140
0
      LM_ERR("pkg memory allocation failure\n");
141
0
      goto error;
142
0
    }
143
0
    memcpy(si->orig_name.s, orig_name->s, orig_name->len);
144
0
    si->orig_name.s[orig_name->len] = '\0';
145
0
    si->orig_name.len = orig_name->len;
146
0
  }
147
148
  /* set port & proto */
149
0
  si->port_no=sid->port;
150
0
  si->proto=sid->proto;
151
0
  si->flags=sid->flags;
152
153
  /* advertised socket information */
154
  /* Make sure the adv_sock_string is initialized, because if there is
155
   * no adv_sock_name, no other code will initialize it!
156
   */
157
0
  si->adv_sock_str.s=NULL;
158
0
  si->adv_sock_str.len=0;
159
0
  si->adv_port = 0; /* Here to help grep_sock_info along. */
160
0
  if(sid->adv_name) {
161
0
    si->adv_name_str.len=strlen(sid->adv_name);
162
0
    si->adv_name_str.s=(char *)pkg_malloc(si->adv_name_str.len+1);
163
0
    if (si->adv_name_str.s==0) goto error;
164
0
    memcpy(si->adv_name_str.s, sid->adv_name, si->adv_name_str.len+1);
165
0
    if (!sid->adv_port) sid->adv_port=si->port_no ;
166
0
    si->adv_port_str.s=pkg_malloc(10);
167
0
    if (si->adv_port_str.s==0) goto error;
168
0
    si->adv_port_str.len=snprintf(si->adv_port_str.s, 10, "%hu",
169
0
      (unsigned short)sid->adv_port);
170
0
    si->adv_port = sid->adv_port;
171
0
  }
172
173
  /* store the tag info too */
174
0
  if (sid->tag) {
175
0
    si->tag.len = strlen(sid->tag);
176
0
    si->tag.s=(char*)pkg_malloc(si->tag.len+1); /* include \0 */
177
0
    if (si->tag.s==0) goto error;
178
0
    memcpy(si->tag.s, sid->tag, si->tag.len+1);
179
0
  }
180
181
0
  if (si->proto!=PROTO_UDP && si->proto!=PROTO_SCTP &&
182
0
          si->proto!=PROTO_HEP_UDP) {
183
0
    if (sid->workers)
184
0
      LM_WARN("number of workers per non UDP-based <%.*s> listener not "
185
0
        "supported -> ignoring...\n", si->name.len, si->name.s);
186
0
    if (sid->auto_scaling_profile)
187
0
      LM_WARN("auto-scaling for non UDP-based <%.*s> listener not "
188
0
        "supported -> ignoring...\n", si->name.len, si->name.s);
189
0
  } else {
190
0
    if (sid->workers)
191
0
      si->workers = sid->workers;
192
0
    si->tos = sid->tos;
193
0
    if (sid->auto_scaling_profile) {
194
0
      si->s_profile = get_scaling_profile(sid->auto_scaling_profile);
195
0
      if (si->s_profile==NULL) {
196
0
        LM_WARN("scaling profile <%s> in listener <%.*s> not defined "
197
0
          "-> ignoring it...\n", sid->auto_scaling_profile,
198
0
          si->name.len, si->name.s);
199
0
      } else {
200
0
        auto_scaling_enabled = 1;
201
0
      }
202
0
    } else if (udp_auto_scaling_profile) {
203
0
      si->s_profile = get_scaling_profile(udp_auto_scaling_profile);
204
0
      if (si->s_profile==NULL) {
205
0
        LM_WARN("scaling profile <%s> in udp_workers not defined "
206
0
          "-> ignoring it...\n", udp_auto_scaling_profile);
207
0
      } else {
208
0
        auto_scaling_enabled = 1;
209
0
      }
210
0
    }
211
0
  }
212
0
  return sif;
213
0
error:
214
0
  LM_ERR("pkg memory allocation error\n");
215
0
  if (sif) {
216
0
    free_sock_info(sif);
217
0
    pkg_free(sif);
218
0
  }
219
0
  return 0;
220
0
}
221
222
223
224
/*  delete a socket_info struct */
225
void free_sock_info(struct socket_info_full* sif)
226
0
{
227
0
  if(sif){
228
0
    struct socket_info_ref *bond_si, *next_bond_si;
229
0
    struct socket_info *si = &sif->socket_info;
230
0
    if(si->name.s) pkg_free(si->name.s);
231
0
    if(si->orig_name.s) pkg_free(si->orig_name.s);
232
0
    if(si->tag.s) pkg_free(si->tag.s);
233
0
    if(si->sock_str.s) pkg_free(si->sock_str.s);
234
0
    if(si->address_str.s) pkg_free(si->address_str.s);
235
0
    if(si->port_no_str.s) pkg_free(si->port_no_str.s);
236
0
    if(si->adv_name_str.s) pkg_free(si->adv_name_str.s);
237
0
    if(si->adv_port_str.s) pkg_free(si->adv_port_str.s);
238
0
    if(si->adv_sock_str.s) pkg_free(si->adv_sock_str.s);
239
0
    if(si->tag_sock_str.s) pkg_free(si->tag_sock_str.s);
240
0
    for (bond_si = si->bond_sis; bond_si; bond_si = next_bond_si) {
241
0
      next_bond_si = bond_si->next;
242
0
      pkg_free(bond_si);
243
0
    }
244
0
  }
245
0
}
246
247
248
static void free_socket_id_list(struct socket_id *list)
249
0
{
250
0
  struct socket_id *sid, *next_sid;
251
0
  struct socket_bond_elem *be, *next_be;
252
253
0
  for (sid = list; sid; sid = next_sid) {
254
0
    next_sid = sid->next;
255
0
    for (be = sid->bond_list; be; be = next_be) {
256
0
      next_be = be->next;
257
0
      if (be->name)
258
0
        pkg_free(be->name);
259
0
      pkg_free(be);
260
0
    }
261
0
    pkg_free(sid);
262
0
  }
263
0
}
264
265
266
int fix_bond_socket_list(struct socket_id *list)
267
0
{
268
0
  struct socket_id *sid;
269
0
  struct socket_id *next_sid;
270
0
  struct socket_bond_elem *be;
271
0
  struct socket_info_full *sif = NULL;
272
0
  struct socket_info_full *orig_sif;
273
0
  struct socket_info_ref *ref;
274
0
  const struct socket_info *bond_si;
275
0
  str bond_spec, host;
276
0
  int port, proto, found_any;
277
278
0
  for (sid = list; sid; sid = next_sid) {
279
280
0
    next_sid = sid->next;
281
282
0
    if (sid->proto!=PROTO_BOND) {
283
0
      LM_BUG("non-bond socket found in the list\n");
284
0
      goto error;
285
0
    }
286
287
0
    sif = new_sock_info(sid, NULL);
288
0
    if (!sif) {
289
0
      LM_ERR("failed to build socket info for bond <%s>\n", sid->name);
290
0
      goto error;
291
0
    }
292
293
0
    for (be = sid->bond_list; be; be = be->next) {
294
0
      bond_spec.s = be->name;
295
0
      bond_spec.len = strlen(be->name);
296
0
      found_any = 0;
297
0
      if (parse_phostport(bond_spec.s, bond_spec.len, &host.s, &host.len,
298
0
          &port, &proto) != 0) {
299
0
        LM_WARN("failed to parse bond member <%s> for bond <%s>\n",
300
0
          be->name, sid->name);
301
0
        continue;
302
0
      }
303
304
0
      bond_si = grep_internal_sock_info(&host, (unsigned short)port,
305
0
        (unsigned short)proto);
306
0
      if (bond_si) {
307
0
        found_any = 1;
308
0
        ref = pkg_malloc(sizeof(*ref));
309
0
        if (!ref) {
310
0
          LM_ERR("pkg memory allocation failed while building "
311
0
            "bond <%s>\n", sid->name);
312
0
          goto error;
313
0
        }
314
0
        ref->si = bond_si;
315
0
        ref->next = sif->socket_info.bond_sis;
316
0
        sif->socket_info.bond_sis = ref;
317
318
0
        LM_DBG("bond socket [%.*s] including real socket [%.*s]\n",
319
0
          sif->socket_info.name.len, sif->socket_info.name.s,
320
0
          bond_si->sock_str.len, bond_si->sock_str.s);
321
0
        continue;
322
0
      }
323
324
0
      orig_sif = NULL;
325
0
      while ((orig_sif = grep_sock_by_orig_name((unsigned short)proto,
326
0
          &host, (unsigned short)port, orig_sif))) {
327
0
        bond_si = &orig_sif->socket_info;
328
329
0
        ref = pkg_malloc(sizeof(*ref));
330
0
        if (!ref) {
331
0
          LM_ERR("pkg memory allocation failed while building "
332
0
            "bond <%s>\n", sid->name);
333
0
          goto error;
334
0
        }
335
0
        ref->si = bond_si;
336
0
        ref->next = sif->socket_info.bond_sis;
337
0
        sif->socket_info.bond_sis = ref;
338
0
        found_any = 1;
339
340
0
        LM_DBG("bond socket [%.*s] including real socket [%.*s] by "
341
0
          "orig_name\n",
342
0
          sif->socket_info.name.len, sif->socket_info.name.s,
343
0
          bond_si->sock_str.len, bond_si->sock_str.s);
344
0
      }
345
346
0
      if (!found_any) {
347
0
        LM_WARN("failed to resolve bond member <%s> for bond <%s>\n",
348
0
          be->name, sid->name);
349
0
      }
350
0
    }
351
352
0
    if (!sif->socket_info.bond_sis) {
353
0
      LM_ERR("bond socket <%s> has no valid members\n", sid->name);
354
0
      goto error;
355
0
    }
356
357
    /* double linked list */
358
0
    sif->next = bond_sockets;
359
0
    if (bond_sockets)
360
0
      bond_sockets->prev = sif;
361
0
    bond_sockets = sif;
362
363
    /* free current element */
364
0
    sid->next = NULL;
365
0
    free_socket_id_list(sid);
366
0
  }
367
368
0
  return 0;
369
0
error:
370
0
  if (sif) {
371
0
    free_sock_info(sif);
372
0
    pkg_free(sif);
373
0
  }
374
0
  free_socket_id_list(sid);
375
0
  return -1;
376
0
}
377
378
379
/* checks if the proto: host:port is one of the address we listen on
380
 * and returns the corresponding socket_info structure.
381
 * if port==0, the  port number is ignored
382
 * if proto==0 (PROTO_NONE) the protocol is ignored
383
 * returns  0 if not found
384
 * WARNING: uses str2ip6 so it will overwrite any previous
385
 *  unsaved result of this function (static buffer)
386
 */
387
const struct socket_info* grep_sock_info_ext(str* host, unsigned short port,
388
                    unsigned short proto, int check_tags)
389
0
{
390
0
  char* hname;
391
0
  int h_len;
392
0
  const struct socket_info* si = NULL;
393
0
  struct socket_info_full* sif;
394
0
  struct socket_info_full ** list;
395
0
  unsigned short c_proto;
396
0
  struct ip_addr* ip6;
397
398
0
  h_len=host->len;
399
0
  hname=host->s;
400
401
0
  if (proto == PROTO_BOND) {
402
0
    if (!check_tags)
403
0
      goto not_found;
404
0
    for (sif = bond_sockets; sif; sif = sif->next) {
405
0
      si = &sif->socket_info;
406
0
      if (h_len == si->name.len &&
407
0
      strncasecmp(hname, si->name.s, si->name.len) == 0)
408
0
        goto found;
409
0
    }
410
0
    goto not_found;
411
0
  }
412
413
0
  if ((h_len>2)&&((*hname)=='[')&&(hname[h_len-1]==']')){
414
    /* ipv6 reference, skip [] */
415
0
    hname++;
416
0
    h_len-=2;
417
0
  }
418
419
0
  c_proto=proto?proto:PROTO_UDP;
420
0
  do{
421
    /* "proto" is all the time valid here */
422
0
    list=get_sock_info_list(c_proto);
423
424
0
    if (list==0){
425
0
      LM_WARN("unknown proto %d\n", c_proto);
426
0
      goto not_found; /* false */
427
0
    }
428
0
    for (sif=*list; sif; sif=sif->next){
429
0
      si = &sif->socket_info;
430
0
      LM_DBG("checking if host==us: %d==%d && "
431
0
          " [%.*s] == [%.*s]\n",
432
0
            h_len,
433
0
            si->name.len,
434
0
            h_len, hname,
435
0
            si->name.len, si->name.s
436
0
        );
437
438
0
      if (check_tags && port==0 && si->tag.s && h_len==si->tag.len &&
439
0
      strncasecmp(hname, si->tag.s, si->tag.len)==0 )
440
0
        goto found;
441
442
0
      if (port) {
443
0
        LM_DBG("checking if port %d matches port %d\n",
444
0
            si->port_no, port);
445
0
        if ((si->port_no != 0 || protos[c_proto].default_port != port) &&
446
0
            (si->port_no == 0 || si->port_no != port) &&
447
0
            si->adv_port!=port) {
448
0
          continue;
449
0
        }
450
0
      }
451
0
      if ( (h_len==si->name.len) &&
452
0
        (strncasecmp(hname, si->name.s,
453
0
             si->name.len)==0) /*slower*/)
454
        /* comp. must be case insensitive, host names
455
         * can be written in mixed case, it will also match
456
         * ipv6 addresses if we are lucky*/
457
0
        goto found;
458
      /* Check if the adv. name of this socket matches */
459
0
      if ( (h_len==si->adv_name_str.len) &&
460
0
        (strncasecmp(hname, si->adv_name_str.s,
461
0
          si->adv_name_str.len)==0) /*slower*/)
462
        /* comp. must be case insensitive, host names
463
        * can be in mixed case, it will also match
464
        * ipv6 addresses if we are lucky*/
465
0
        goto found;
466
      /* if no advertised is specified on the interface, we should check
467
       * if it is the global address */
468
0
      if (!si->adv_name_str.len && default_global_address->s &&
469
0
        h_len == default_global_address->len &&
470
0
        (strncasecmp(hname, default_global_address->s,
471
0
          default_global_address->len)==0) /*slower*/)
472
        /* this might match sockets that are not supposed to
473
         * match, when using multiple listeners for the same
474
         * protocol; but in that case the default_global_address
475
         * concept is broken, since there is no way to choose
476
         * the right socket */
477
0
        goto found;
478
      /* check if host == ip address */
479
      /* ipv6 case is uglier, host can be [3ffe::1] */
480
0
      ip6=str2ip6(host);
481
0
      if (ip6){
482
0
        if (ip_addr_cmp(ip6, &si->address))
483
0
          goto found; /* match */
484
0
        else
485
0
        if (si->adv_name_str.len && ip_addr_cmp(ip6,&si->adv_address))
486
0
          goto found;
487
0
        else
488
0
          continue; /* no match, but this is an ipv6 address
489
                 so no point in trying ipv4 */
490
0
      }
491
      /* ipv4 */
492
0
      if (  (!(si->flags&SI_IS_IP)) &&
493
0
          (h_len==si->address_str.len) &&
494
0
        (memcmp(hname, si->address_str.s,
495
0
                  si->address_str.len)==0)
496
0
        )
497
0
        goto found;
498
0
    }
499
0
  }while( (proto==0) && (c_proto=next_proto(c_proto)) );
500
0
not_found:
501
0
  return 0;
502
0
found:
503
0
  return si;
504
0
}
505
506
507
508
/* checks if the proto: ip:port is one of the address we listen on
509
 * and returns the corresponding socket_info structure.
510
 * (same as grep_socket_info, but use ip addr instead)
511
 * if port==0, the  port number is ignored
512
 * if proto==0 (PROTO_NONE) the protocol is ignored
513
 * returns  0 if not found
514
 * WARNING: uses str2ip6 so it will overwrite any previous
515
 *  unsaved result of this function (static buffer)
516
 */
517
const struct socket_info* find_si(const struct ip_addr* ip, unsigned short port,
518
                        unsigned short proto)
519
0
{
520
0
  const struct socket_info* si = NULL;
521
0
  struct socket_info_full* sif;
522
0
  struct socket_info_full** list;
523
0
  unsigned short c_proto;
524
525
0
  c_proto=proto?proto:PROTO_UDP;
526
0
  do{
527
    /* get the proper sock_list */
528
0
    list=get_sock_info_list(c_proto);
529
530
0
    if (list==0){
531
0
      LM_WARN("unknown proto %d\n", c_proto);
532
0
      goto not_found; /* false */
533
0
    }
534
0
    for (sif=*list; sif; sif=sif->next){
535
0
      si = &sif->socket_info;
536
0
      if (port) {
537
0
        if (si->port_no!=port) {
538
0
          continue;
539
0
        }
540
0
      }
541
0
      if (ip_addr_cmp(ip, &si->address) || ip_addr_cmp(ip, &si->adv_address))
542
0
        goto found;
543
0
    }
544
0
  }while( (proto==0) && (c_proto=next_proto(c_proto)) );
545
0
not_found:
546
0
  return 0;
547
0
found:
548
0
  return si;
549
0
}
550
551
552
/* parses the specified `spec` and returns an associated
553
 * socket_info*, if it could be found */
554
const struct socket_info* parse_sock_info(str *addr)
555
0
{
556
0
  int port, proto;
557
0
  str host;
558
559
0
  if (!addr || !addr->s)
560
0
    return NULL;
561
562
0
  if (parse_phostport(addr->s, addr->len, &host.s, &host.len,
563
0
    &port, &proto) != 0) {
564
0
    return NULL;
565
0
  }
566
567
0
  return grep_internal_sock_info(&host, (unsigned short) port,
568
0
    (unsigned short) proto);
569
0
}
570
571
struct socket_info_full* grep_sock_by_orig_name(unsigned short proto, str *host,
572
    unsigned short port, struct socket_info_full *resume)
573
0
{
574
0
  struct socket_info_full *sif, **list;
575
0
  str *name;
576
577
0
  if (!host || !host->s)
578
0
    return NULL;
579
580
0
  if (proto == PROTO_NONE)
581
0
    proto = PROTO_UDP;
582
0
  if (proto >= PROTO_LAST || protos[proto].id == PROTO_NONE)
583
0
    return NULL;
584
585
0
  if (resume)
586
0
    sif = resume->next;
587
0
  else {
588
0
    list = get_sock_info_list(proto);
589
0
    if (!list || !*list)
590
0
      return NULL;
591
0
    sif = *list;
592
0
  }
593
594
0
  for (; sif; sif = sif->next) {
595
0
    name = &sif->socket_info.orig_name;
596
0
    if (!name->s)
597
0
      continue;
598
0
    if (name->len != host->len ||
599
0
        memcmp(name->s, host->s, name->len) != 0)
600
0
      continue;
601
602
0
    if (port && (sif->socket_info.port_no != 0 ||
603
0
        protos[proto].default_port != port) &&
604
0
        (sif->socket_info.port_no == 0 ||
605
0
        sif->socket_info.port_no != port) &&
606
0
        sif->socket_info.adv_port != port)
607
0
      continue;
608
609
0
    return sif;
610
0
  }
611
612
0
  return NULL;
613
0
}
614
615
616
/* adds a new sock_info structure to the corresponding list
617
 * return  0 on success, -1 on error */
618
int new_sock2list(struct socket_id *sid, str *orig_name,
619
    struct socket_info_full** list)
620
0
{
621
0
  struct socket_info_full* si;
622
623
0
  si = new_sock_info(sid, orig_name);
624
0
  if (si==0){
625
0
    LM_ERR("new_sock_info failed\n");
626
0
    goto error;
627
0
  }
628
629
0
  sock_listadd(list, si);
630
0
  return 0;
631
0
error:
632
0
  return -1;
633
0
}
634
635
void push_sock2list(struct socket_info_full *si)
636
0
{
637
0
  sock_listadd(&protos[si->socket_info.proto].listeners, si);
638
0
}
639
640
void pop_sock2list(struct socket_info_full *si)
641
0
{
642
0
  sock_listrm(&protos[si->socket_info.proto].listeners, si);
643
0
}
644
645
int update_default_socket_info(struct socket_info *si)
646
0
{
647
0
  switch (si->address.af) {
648
0
    case AF_INET:
649
0
      if (protos[si->proto].sendipv4 &&
650
0
          (protos[si->proto].sendipv4->flags&SI_IS_LO) == 0)
651
0
        return 0;
652
0
      protos[si->proto].sendipv4 = si;
653
0
      return 1;
654
0
    case AF_INET6:
655
0
      if (protos[si->proto].sendipv6 &&
656
0
          (protos[si->proto].sendipv6->flags&SI_IS_LO) == 0)
657
0
        return 0;
658
0
      protos[si->proto].sendipv6 = si;
659
0
      return 1;
660
0
    default:
661
      /* do nothing */
662
0
      return 0;
663
0
  }
664
0
}
665
666
void remove_default_socket_info(struct socket_info *si)
667
0
{
668
0
  struct socket_info_full *sif;
669
0
  switch (si->address.af) {
670
0
    case AF_INET:
671
0
      if (si != protos[si->proto].sendipv4)
672
0
        return;
673
0
      protos[si->proto].sendipv4 = NULL;
674
0
      break;
675
0
    case AF_INET6:
676
0
      if (si != protos[si->proto].sendipv6)
677
0
        return;
678
0
      protos[si->proto].sendipv6 = NULL;
679
0
      break;
680
0
    default:
681
      /* do nothing */
682
0
      return;
683
0
  }
684
0
  for (sif = protos[si->proto].listeners; sif; sif = sif->next)
685
0
    if (update_default_socket_info(&sif->socket_info))
686
0
      return;
687
0
}
688
689
/* add all family type addresses of interface if_name to the socket_info array
690
 * WARNING: it only works with ipv6 addresses on FreeBSD
691
 * return: -1 on error, 0 on success
692
 */
693
static int expand_interface(const struct socket_info *si, struct socket_info_full** list)
694
0
{
695
0
  int ret = -1;
696
0
  struct ip_addr addr;
697
0
  struct socket_id sid;
698
0
  str orig_name = si->name;
699
700
0
  sid.port = si->port_no;
701
0
  sid.proto = si->proto;
702
0
  sid.workers = si->workers;
703
0
  sid.tos = si->tos;
704
0
  sid.auto_scaling_profile = si->s_profile?si->s_profile->name:NULL;
705
0
  sid.adv_port = si->adv_port;
706
0
  sid.adv_name = si->adv_name_str.s; /* it is NULL terminated */
707
0
  sid.tag = si->tag.s; /* it is NULL terminated */
708
0
#ifdef HAVE_IFADDRS
709
  /* use the getifaddrs interface to get all the interfaces */
710
0
  struct ifaddrs *addrs;
711
0
  struct ifaddrs *it;
712
713
0
  if (getifaddrs(&addrs) != 0) {
714
0
    LM_ERR("cannot get interfaces list: %s(%d)\n", strerror(errno), errno);
715
0
    return -1;
716
0
  }
717
718
0
  for (it = addrs; it; it = it->ifa_next) {
719
0
    if (!it->ifa_addr)
720
0
      continue;
721
722
0
    if (si->name.len == 0 || (strcmp(si->name.s, it->ifa_name) == 0)) {
723
0
      if (it->ifa_addr->sa_family != AF_INET &&
724
0
          it->ifa_addr->sa_family != AF_INET6)
725
0
        continue;
726
      /*
727
       * if it is ipv6, and there was no explicit interface specified,
728
       * make sure we don't add any "scoped" interface
729
       */
730
0
      if (it->ifa_addr->sa_family == AF_INET6 &&
731
0
          (((struct sockaddr_in6 *)(void *)it->ifa_addr)->sin6_scope_id != 0))
732
733
0
        continue;
734
0
      sockaddr2ip_addr(&addr, it->ifa_addr);
735
0
      if ((sid.name = ip_addr2a(&addr)) == 0)
736
0
        goto end;
737
0
      sid.flags = si->flags;
738
0
      if (it->ifa_flags & IFF_LOOPBACK)
739
0
        sid.flags |= SI_IS_LO;
740
0
      if (new_sock2list(&sid, &orig_name, list) != 0) {
741
0
        LM_ERR("clone_sock2list failed\n");
742
0
        goto end;
743
0
      }
744
0
      ret = 0;
745
0
    }
746
0
  }
747
0
end:
748
0
  freeifaddrs(addrs);
749
0
  return ret;
750
#else
751
  struct ifconf ifc;
752
  struct ifreq ifr;
753
  struct ifreq ifrcopy;
754
  char*  last;
755
  char* p;
756
  int size;
757
  int lastlen;
758
  int s;
759
760
#ifdef HAVE_SOCKADDR_SA_LEN
761
  #ifndef MAX
762
    #define MAX(a,b) ( ((a)>(b))?(a):(b))
763
  #endif
764
#endif
765
  /* ipv4 or ipv6 only*/
766
  s=socket(AF_INET, SOCK_DGRAM, 0);
767
  lastlen=0;
768
  ifc.ifc_req=0;
769
  for (size=100; ; size*=2){
770
    ifc.ifc_len=size*sizeof(struct ifreq);
771
    ifc.ifc_req=(struct ifreq*) pkg_malloc(size*sizeof(struct ifreq));
772
    if (ifc.ifc_req==0){
773
      LM_ERR("memory allocation failure\n");
774
      goto error;
775
    }
776
    if (ioctl(s, SIOCGIFCONF, &ifc)==-1){
777
      if(errno==EBADF) goto error; /* invalid descriptor => no such ifs*/
778
      LM_ERR("ioctl failed: %s\n", strerror(errno));
779
      goto error;
780
    }
781
    if  ((lastlen) && (ifc.ifc_len==lastlen)) break; /*success,
782
                               len not changed*/
783
    lastlen=ifc.ifc_len;
784
    /* try a bigger array*/
785
    pkg_free(ifc.ifc_req);
786
  }
787
788
  last=(char*)ifc.ifc_req+ifc.ifc_len;
789
  for(p=(char*)ifc.ifc_req; p<last;
790
      p+=
791
      #ifdef __OS_linux
792
        sizeof(ifr) /* works on x86_64 too */
793
      #else
794
        (sizeof(ifr.ifr_name)+
795
        #ifdef  HAVE_SOCKADDR_SA_LEN
796
          MAX(ifr.ifr_addr.sa_len, sizeof(struct sockaddr))
797
        #else
798
          ( (ifr.ifr_addr.sa_family==AF_INET)?
799
            sizeof(struct sockaddr_in):
800
            ((ifr.ifr_addr.sa_family==AF_INET6)?
801
            sizeof(struct sockaddr_in6):sizeof(struct sockaddr)) )
802
        #endif
803
        )
804
      #endif
805
    )
806
  {
807
    /* copy contents into ifr structure
808
     * warning: it might be longer (e.g. ipv6 address) */
809
    memcpy(&ifr, p, sizeof(ifr));
810
    if (ifr.ifr_addr.sa_family!=AF_INET){
811
      /*printf("strange family %d skipping...\n",
812
          ifr->ifr_addr.sa_family);*/
813
      continue;
814
    }
815
816
    /*get flags*/
817
    ifrcopy=ifr;
818
    if (ioctl(s, SIOCGIFFLAGS,  &ifrcopy)!=-1){ /* ignore errors */
819
      /* ignore down ifs only if listening on all of them*/
820
      if (si->name.len==0){
821
        /* if if not up, skip it*/
822
        if (!(ifrcopy.ifr_flags & IFF_UP)) continue;
823
      }
824
    }
825
826
    if (si->name.len == 0 ||
827
      strncmp(si->name.s, ifr.ifr_name, sizeof(ifr.ifr_name))==0){
828
829
      /*add address*/
830
      sockaddr2ip_addr(&addr,
831
          (struct sockaddr*)(p+(long)&((struct ifreq*)0)->ifr_addr));
832
      if ((sid.name=ip_addr2a(&addr))==0) goto error;
833
      sid.flags = si->flags;
834
      /* check if loopback */
835
      if (ifrcopy.ifr_flags & IFF_LOOPBACK)
836
        sid.flags|=SI_IS_LO;
837
      /* add it to one of the lists */
838
      if (new_sock2list(&sid, &orig_name, list) != 0) {
839
        LM_ERR("clone_sock2list failed\n");
840
        goto error;
841
      }
842
      ret=0;
843
    }
844
      /*
845
      printf("%s:\n", ifr->ifr_name);
846
      printf("        ");
847
      print_sockaddr(&(ifr->ifr_addr));
848
      printf("        ");
849
      ls_ifflags(ifr->ifr_name, family, options);
850
      printf("\n");*/
851
  }
852
  pkg_free(ifc.ifc_req); /*clean up*/
853
  close(s);
854
  return  ret;
855
error:
856
  if (ifc.ifc_req) pkg_free(ifc.ifc_req);
857
  if (s >= 0)
858
    close(s);
859
  return -1;
860
#endif
861
0
}
862
863
864
0
#define STR_IMATCH(str, buf) ((str).len==strlen(buf) && strncasecmp(buf, (str).s, (str).len)==0)
865
0
#define ACCEPT_SUBDOMAIN_ALIAS(flags) flags & SI_ACCEPT_SUBDOMAIN_ALIAS
866
867
int is_localhost(struct socket_info *si)
868
0
{
869
0
  return (STR_IMATCH(si->name, "localhost") ||
870
0
      STR_IMATCH(si->name, "127.0.0.1") ||
871
0
      STR_IMATCH(si->name, "0:0:0:0:0:0:0:1") || STR_IMATCH(si->name, "::1"));
872
0
}
873
874
int fix_socket(struct socket_info_full *sif, int add_aliases)
875
0
{
876
0
  char** h;
877
0
  char* tmp;
878
0
  int len;
879
0
  struct hostent* he;
880
0
  struct socket_info *si = &sif->socket_info;
881
882
  /* fix the number of processes per interface */
883
0
  if (!si->workers && is_udp_based_proto(si->proto))
884
0
    si->workers = udp_workers_no;
885
0
  if (si->port_no==0)
886
0
    si->port_no= protos[si->proto].default_port;
887
888
0
  tmp=int2str(si->port_no, &len);
889
0
  if (len>=MAX_PORT_LEN){
890
0
    LM_ERR("bad port number: %d\n", si->port_no);
891
0
    return -1;
892
0
  }
893
894
0
  si->port_no_str.s=(char*)pkg_malloc(len+1);
895
0
  if (si->port_no_str.s==0){
896
0
    LM_ERR("out of pkg memory.\n");
897
0
    goto error;
898
0
  }
899
0
  memcpy(si->port_no_str.s, tmp, len+1);
900
0
  si->port_no_str.len=len;
901
  /* get "official hostnames", all the aliases etc. */
902
0
  he=resolvehost(si->name.s,0);
903
0
  if (he==0){
904
0
    LM_ERR("could not resolve %s\n", si->name.s);
905
0
    goto error;
906
0
  }
907
  /* check if we got the official name */
908
0
  if (strcasecmp(he->h_name, si->name.s)!=0){
909
0
    if (add_aliases && add_alias(si->name.s, si->name.len,
910
0
        si->port_no, si->proto, ACCEPT_SUBDOMAIN_ALIAS(si->flags))<0){
911
0
      LM_ERR("add_alias failed\n");
912
0
    }
913
    /* change the official name */
914
0
    pkg_free(si->name.s);
915
0
    si->name.s=(char*)pkg_malloc(strlen(he->h_name)+1);
916
0
    if (si->name.s==0){
917
0
      LM_ERR("out of pkg memory.\n");
918
0
      goto error;
919
0
    }
920
0
    si->name.len=strlen(he->h_name);
921
0
    memcpy(si->name.s, he->h_name, si->name.len+1);
922
0
  }
923
  /* add the aliases*/
924
0
  if (add_aliases) {
925
0
    for(h=he->h_aliases; h && *h; h++)
926
0
      if (add_alias(*h, strlen(*h), si->port_no, si->proto,
927
0
              ACCEPT_SUBDOMAIN_ALIAS(si->flags))<0){
928
0
        LM_ERR("add_alias failed\n");
929
0
      }
930
0
  }
931
0
  hostent2ip_addr(&si->address, he, 0); /*convert to ip_addr
932
                           format*/
933
0
  if ((tmp=ip_addr2a(&si->address))==0) goto error;
934
0
  if (si->address.af == AF_INET6) {
935
0
    si->address_str.s=(char*)pkg_malloc(strlen(tmp)+1+2);
936
0
    if (si->address_str.s==0){
937
0
      LM_ERR("out of pkg memory.\n");
938
0
      goto error;
939
0
    }
940
0
    si->address_str.s[0] = '[';
941
0
    memcpy( si->address_str.s+1 , tmp, strlen(tmp));
942
0
    si->address_str.s[1+strlen(tmp)] = ']';
943
0
    si->address_str.s[2+strlen(tmp)] = '\0';
944
0
    si->address_str.len=strlen(tmp) + 2;
945
0
  } else {
946
0
    si->address_str.s=(char*)pkg_malloc(strlen(tmp)+1);
947
0
    if (si->address_str.s==0){
948
0
      LM_ERR("out of pkg memory.\n");
949
0
      goto error;
950
0
    }
951
0
    memcpy(si->address_str.s, tmp, strlen(tmp)+1);
952
0
    si->address_str.len=strlen(tmp);
953
0
  }
954
  /* set is_ip (1 if name is an ip address, 0 otherwise) */
955
0
  if ( auto_aliases && (si->address_str.len==si->name.len) &&
956
0
      (strncasecmp(si->address_str.s, si->name.s,
957
0
              si->address_str.len)==0)
958
0
    ){
959
0
      si->flags|=SI_IS_IP;
960
      /* do rev. DNS on it (for aliases)*/
961
0
      he=rev_resolvehost(&si->address);
962
0
      if (he==0){
963
0
        LM_WARN("could not rev. resolve %s\n", si->name.s);
964
0
      }else{
965
        /* add the aliases*/
966
0
        if (add_alias(he->h_name, strlen(he->h_name),
967
0
          si->port_no, si->proto, ACCEPT_SUBDOMAIN_ALIAS(si->flags))<0){
968
0
          LM_ERR("add_alias failed\n");
969
0
        }
970
0
        for(h=he->h_aliases; h && *h; h++)
971
0
          if (add_alias(*h,strlen(*h),si->port_no,si->proto,
972
0
            ACCEPT_SUBDOMAIN_ALIAS(si->flags))<0){
973
0
            LM_ERR(" add_alias failed\n");
974
0
          }
975
0
      }
976
0
  }
977
978
  /* Now build an ip_addr structure for the adv_name, if there is one
979
   * so that find_si can find it later easily.  Doing this so that
980
   * we can force_send_socket() on an advertised name.  Generally there
981
   * is little interest in dealing with an advertised name as anything
982
   * other than an opaque string that we blindly put into the SIP
983
   * message.
984
   */
985
0
    if(si->adv_name_str.len) {
986
    /* If adv_name_str is already an IP, this is kinda foolish cus it
987
     * converts it to ip_addr, then to he, then here we go back to
988
     * ip_addr, but it's either that, or we duplicate the logic to
989
     * check for an ip address here, and still we might have to call
990
     * resolvehost().
991
     */
992
0
    he=resolvehost(si->adv_name_str.s,0);
993
0
    if (he==0){
994
0
      LM_ERR("ERROR: fix_socket_list: could not resolve "
995
0
          "advertised name %s\n", si->adv_name_str.s);
996
0
      goto error;
997
0
    }
998
0
    hostent2ip_addr(&si->adv_address, he, 0); /*convert to ip_addr */
999
1000
0
    if (si->adv_address.af == AF_INET6 /* translates to IPv6 */
1001
0
    && str2ip6(&si->adv_name_str)!=NULL /* it's an actual IP */
1002
0
    && si->adv_name_str.s[0]!='['  )    /* not enclosed */
1003
0
    {
1004
0
      tmp = pkg_malloc( si->adv_name_str.len +2 );
1005
0
      if (tmp==NULL) {
1006
0
        LM_ERR("failed to convert advertized IPv6 "
1007
0
          "to enclosed format\n");
1008
0
        goto error;
1009
0
      }
1010
0
      tmp[0] = '[';
1011
0
      memcpy( tmp+1, si->adv_name_str.s, si->adv_name_str.len);
1012
0
      tmp[si->adv_name_str.len+1] = ']';
1013
0
      pkg_free(si->adv_name_str.s);
1014
0
      si->adv_name_str.s = tmp;
1015
0
      si->adv_name_str.len += 2;
1016
0
    }
1017
1018
    /* build and set string encoding for the adv socket info
1019
     * This is usefful for the usrloc module when it's generating
1020
     * or updating the socket on a location record, so we'll generate
1021
     * it up front just like the regular sock_str so we don't have
1022
     * to worry about it later.
1023
     */
1024
0
    tmp = socket2str( si, 0, &si->adv_sock_str.len, 1);
1025
0
    if (tmp==0) {
1026
0
      LM_ERR("ERROR: fix_socket_list: failed to convert "
1027
0
            "socket to string (adv)\n");
1028
0
      goto error;
1029
0
    }
1030
0
    si->adv_sock_str.s=(char*)pkg_malloc(si->adv_sock_str.len);
1031
0
    if (si->adv_sock_str.s==0) {
1032
0
      LM_ERR("ERROR: fix_socket_list: out of memory.\n");
1033
0
      goto error;
1034
0
    }
1035
0
    memcpy(si->adv_sock_str.s, tmp, si->adv_sock_str.len);
1036
0
  }
1037
1038
0
  if (si->tag.len) {
1039
    /* build and set string encoding for the tagged socket info */
1040
0
    tmp = socket2str( si, 0, &si->tag_sock_str.len, 2);
1041
0
    if (tmp==0) {
1042
0
      LM_ERR("failed to convert tag socket to string\n");
1043
0
      goto error;
1044
0
    }
1045
0
    si->tag_sock_str.s=(char*)pkg_malloc(si->tag_sock_str.len);
1046
0
    if (si->tag_sock_str.s==0) {
1047
0
      LM_ERR("out of pkg memory.\n");
1048
0
      goto error;
1049
0
    }
1050
0
    memcpy(si->tag_sock_str.s, tmp, si->tag_sock_str.len);
1051
0
  }
1052
1053
  /* build and set string encoding for the real socket info */
1054
0
  tmp = socket2str( si, 0, &si->sock_str.len, 0);
1055
0
  if (tmp==0) {
1056
0
    LM_ERR("failed to convert socket to string\n");
1057
0
    goto error;
1058
0
  }
1059
0
  si->sock_str.s=(char*)pkg_malloc(si->sock_str.len);
1060
0
  if (si->sock_str.s==0) {
1061
0
    LM_ERR("out of pkg memory.\n");
1062
0
    goto error;
1063
0
  }
1064
0
  memcpy(si->sock_str.s, tmp, si->sock_str.len);
1065
1066
#ifdef USE_MCAST
1067
  /* Check if it is an multicast address and
1068
   * set the flag if so
1069
   */
1070
  if (is_mcast(&si->address)) {
1071
    si->flags |= SI_IS_MCAST;
1072
  }
1073
#endif /* USE_MCAST */
1074
1075
#ifdef EXTRA_DEBUG
1076
  printf("              %.*s [%s]:%s%s%s\n", si->name.len,
1077
    si->name.s, si->address_str.s, si->port_no_str.s,
1078
                  si->flags & SI_IS_MCAST ? " mcast" : "",
1079
                  is_anycast(si) ? " anycast" : "");
1080
#endif
1081
0
  return 0;
1082
0
error:
1083
0
  return -1;
1084
0
}
1085
1086
/* fixes a socket list => resolve addresses,
1087
 * interface names, fills missing members, remove duplicates */
1088
int fix_socket_list(struct socket_info_full **list)
1089
0
{
1090
0
  struct socket_info_full* sif;
1091
0
  struct socket_info* si;
1092
0
  struct socket_info_full* l;
1093
0
  struct socket_info_full* next;
1094
1095
  /* try to change all the interface names into addresses
1096
   *  --ugly hack */
1097
1098
0
  for (sif=*list;sif;){
1099
0
    next=sif->next;
1100
0
    si = &sif->socket_info;
1101
    // fix the SI_IS_LO flag for sockets specified by IP/hostname as expand_interface
1102
    // below will only do it for sockets specified using the network interface name
1103
0
    if (is_localhost(si))
1104
0
      si->flags |= SI_IS_LO;
1105
0
    if (expand_interface(si, list)!=-1){
1106
      /* success => remove current entry (shift the entire array)*/
1107
0
      sock_listrm(list, sif);
1108
0
      free_sock_info(sif);
1109
0
    }
1110
0
    sif=next;
1111
0
  }
1112
  /* get ips & fill the port numbers*/
1113
#ifdef EXTRA_DEBUG
1114
  LM_DBG("listening on \n");
1115
#endif
1116
0
  for (sif=*list;sif;sif=sif->next){
1117
0
    si = &sif->socket_info;
1118
0
    if (fix_socket(sif, auto_aliases) < 0) {
1119
0
      sock_listrm(list, sif);
1120
0
      free_sock_info(sif);
1121
0
    }
1122
0
  }
1123
  /* removing duplicate addresses*/
1124
0
  for (sif=*list;sif; sif=sif->next){
1125
0
    for (l=sif->next;l;){
1126
0
      next=l->next;
1127
0
      si = &sif->socket_info;
1128
0
      const struct socket_info *sl = &l->socket_info;
1129
0
      if ((si->port_no==sl->port_no) &&
1130
0
        (si->address.af==sl->address.af) &&
1131
0
        (memcmp(si->address.u.addr, sl->address.u.addr, si->address.len)
1132
0
          == 0)
1133
0
        ){
1134
#ifdef EXTRA_DEBUG
1135
        printf("removing duplicate %s [%s] ==  %s [%s]\n",
1136
            si->name.s, si->address_str.s,
1137
             sl->name.s, sl->address_str.s);
1138
#endif
1139
        /* add the name to the alias list*/
1140
0
        if ((!(sl->flags& SI_IS_IP)) && (
1141
0
            (sl->name.len!=si->name.len)||
1142
0
            (strncmp(sl->name.s, si->name.s, si->name.len)!=0))
1143
0
          )
1144
0
          if (add_alias(sl->name.s,sl->name.len,sl->port_no,sl->proto,
1145
0
              ACCEPT_SUBDOMAIN_ALIAS(sl->flags))<0)
1146
0
            LM_ERR(" add_alias failed\n");
1147
1148
        /* remove l*/
1149
0
        sock_listrm(list, l);
1150
0
        free_sock_info(l);
1151
0
      }
1152
0
      l=next;
1153
0
    }
1154
0
  }
1155
1156
#ifdef USE_MCAST
1157
       /* Remove invalid multicast entries */
1158
  sif=*list;
1159
  while(sif){
1160
    si = &sif->socket_info;
1161
    if ((si->flags & SI_IS_MCAST) &&
1162
        (si->proto != PROTO_UDP)
1163
       ){
1164
      LM_WARN("removing entry %s:%s [%s]:%s\n",
1165
          get_proto_name(si->proto), si->name.s,
1166
          si->address_str.s, si->port_no_str.s);
1167
      l = sif;
1168
      sif=sif->next;
1169
      sock_listrm(list, l);
1170
      free_sock_info(l);
1171
    } else {
1172
      sif=sif->next;
1173
    }
1174
  }
1175
#endif /* USE_MCAST */
1176
1177
0
  return 0;
1178
0
}
1179
1180
1181
1182
1183
1184
/*
1185
 * This function will retrieve a list of all ip addresses and ports that
1186
 * OpenSIPS is listening on, with respect to the transport protocol specified
1187
 * with 'protocol'.
1188
 *
1189
 * The first parameter, ipList, is a pointer to a pointer. It will be assigned
1190
 * a new block of memory holding the IP Addresses and ports being listened to 
1191
 * with respect to 'protocol'.  The array maps a 2D array into a 1 dimensional 
1192
 * space, and is layed out as follows:
1193
 *
1194
 * The first NUM_IP_OCTETS indices will be the IP address, and the next index
1195
 * the port.  So if NUM_IP_OCTETS is equal to 4 and there are two IP addresses
1196
 * found, then:
1197
 *
1198
 *  - ipList[0] will be the first octet of the first ip address
1199
 *  - ipList[3] will be the last octet of the first ip address.
1200
 *  - iplist[4] will be the port of the first ip address
1201
 *  -
1202
 *  - iplist[5] will be the first octet of the first ip address,
1203
 *  - and so on.
1204
 *
1205
 * The function will return the number of sockets which were found.  This can
1206
 * be used to index into ipList.
1207
 *
1208
 * NOTE: This function assigns a block of memory equal to:
1209
 *
1210
 *            returnedValue * (NUM_IP_OCTETS + 1) * sizeof(int);
1211
 *
1212
 *       Therefore it is CRUCIAL that you free ipList when you are done with
1213
 *       its contents, to avoid a nasty memory leak.
1214
 */
1215
0
int get_socket_list_from_proto(unsigned int **ipList, int protocol) {
1216
1217
0
  struct socket_info_full  *sif;
1218
0
  struct socket_info_full ** list;
1219
1220
0
  int num_ip_octets   = 4;
1221
0
  int numberOfSockets = 0;
1222
0
  int currentRow      = 0;
1223
1224
  /* I hate to use #ifdefs, but this is necessary because of the way
1225
   * get_sock_info_list() is defined.  */
1226
0
  if (protocol == PROTO_TCP)
1227
0
  {
1228
0
    return 0;
1229
0
  }
1230
1231
0
  if (protocol == PROTO_TLS)
1232
0
  {
1233
0
    return 0;
1234
0
  }
1235
1236
  /* Retrieve the list of sockets with respect to the given protocol. */
1237
0
  list=get_sock_info_list(protocol);
1238
1239
  /* Find out how many sockets are in the list.  We need to know this so
1240
   * we can malloc an array to assign to ipList. */
1241
0
  for(sif=list?*list:0; sif; sif=sif->next){
1242
    /* We only support IPV4 at this point. */
1243
0
    if (sif->socket_info.address.af == AF_INET) {
1244
0
      numberOfSockets++;
1245
0
    }
1246
0
  }
1247
1248
  /* There are no open sockets with respect to the given protocol. */
1249
0
  if (numberOfSockets == 0)
1250
0
  {
1251
0
    return 0;
1252
0
  }
1253
1254
0
  *ipList = pkg_malloc(numberOfSockets *
1255
0
      (num_ip_octets + 1) * (int)sizeof(int));
1256
1257
  /* We couldn't allocate memory for the IP List.  So all we can do is
1258
   * fail. */
1259
0
  if (*ipList == NULL) {
1260
0
    LM_ERR("no more pkg memory");
1261
0
    return 0;
1262
0
  }
1263
1264
1265
  /* We need to search the list again.  So find the front of the list. */
1266
0
  list=get_sock_info_list(protocol);
1267
1268
  /* Extract out the IP Addresses and ports.  */
1269
0
  for(sif=list?*list:0; sif; sif=sif->next){
1270
0
    const struct socket_info *si = &sif->socket_info;
1271
1272
    /* We currently only support IPV4. */
1273
0
    if (si->address.af != AF_INET) {
1274
0
      continue;
1275
0
    }
1276
1277
0
    (*ipList)[currentRow*(num_ip_octets + 1)  ] =
1278
0
      si->address.u.addr[0];
1279
0
    (*ipList)[currentRow*(num_ip_octets + 1)+1] =
1280
0
      si->address.u.addr[1];
1281
0
    (*ipList)[currentRow*(num_ip_octets + 1)+2] =
1282
0
      si->address.u.addr[2];
1283
0
    (*ipList)[currentRow*(num_ip_octets + 1)+3] =
1284
0
      si->address.u.addr[3];
1285
0
    (*ipList)[currentRow*(num_ip_octets + 1)+4] =
1286
0
      si->port_no;
1287
1288
0
    currentRow++;
1289
0
  }
1290
1291
0
  return numberOfSockets;
1292
0
}
1293
1294
/*
1295
 * Takes a 'line' (from the proc file system), parses out the ipAddress,
1296
 * address, and stores the number of bytes waiting in 'rx_queue'
1297
 *
1298
 * Returns 1 on success, and 0 on a failed parse.
1299
 *
1300
 * Note: The format of ipAddress is as defined in the comments of
1301
 * get_socket_list_from_proto() in this file.
1302
 *
1303
 */
1304
static int parse_proc_net_line(char *line, unsigned int *ipAddress, int *rx_queue)
1305
0
{
1306
0
  int i;
1307
1308
0
  unsigned int ipOctetExtractionMask = 0xFF;
1309
1310
0
  char *currColonLocation;
1311
0
  char *nextNonNumericalChar;
1312
0
  char *currentLocationInLine = line;
1313
1314
0
  unsigned int parsedInteger[4];
1315
1316
  /* Example line from /proc/net/tcp or /proc/net/udp:
1317
   *
1318
   *  sl  local_address rem_address   st tx_queue rx_queue
1319
   *  21: 5A0A0B0A:CAC7 1C016E0A:0016 01 00000000:00000000
1320
   *
1321
   * Algorithm:
1322
   *
1323
   *  1) Find the location of the first  ':'
1324
   *  2) Parse out the IP Address into an integer
1325
   *  3) Find the location of the second ':'
1326
   *  4) Parse out the port number.
1327
   *  5) Find the location of the fourth ':'
1328
   *  6) Parse out the rx_queue.
1329
   */
1330
1331
0
  for (i = 0; i < 4; i++) {
1332
1333
0
    currColonLocation = strchr(currentLocationInLine, ':');
1334
1335
    /* We didn't find all the needed ':', so fail. */
1336
0
    if (currColonLocation == NULL) {
1337
0
      return 0;
1338
0
    }
1339
1340
    /* Parse out the integer, keeping the location of the next
1341
     * non-numerical character.  */
1342
0
    parsedInteger[i] =
1343
0
      (int) strtol(++currColonLocation, &nextNonNumericalChar,
1344
0
          16);
1345
1346
    /* strtol()'s specifications specify that the second parameter
1347
     * is set to the first parameter when a number couldn't be
1348
     * parsed out.  This means the parse was unsuccesful.  */
1349
0
    if (nextNonNumericalChar == currColonLocation) {
1350
0
      return 0;
1351
0
    }
1352
1353
    /* Reset the currentLocationInLine to the last non-numerical
1354
     * character, so that next iteration of this loop, we can find
1355
     * the next colon location. */
1356
0
    currentLocationInLine = nextNonNumericalChar;
1357
1358
0
  }
1359
1360
  /* Extract out the segments of the IP Address.  They are stored in
1361
   * reverse network byte order. */
1362
0
  for (i = 0; i < NUM_IP_OCTETS; i++) {
1363
1364
0
    ipAddress[i] =
1365
0
      parsedInteger[0] & (ipOctetExtractionMask << i*8);
1366
1367
0
    ipAddress[i] >>= i*8;
1368
1369
0
  }
1370
1371
0
  ipAddress[NUM_IP_OCTETS] = parsedInteger[1];
1372
1373
0
  *rx_queue = parsedInteger[3];
1374
1375
0
  return 1;
1376
1377
0
}
1378
1379
1380
/*
1381
 * Returns 1 if ipOne was found in ipArray, and 0 otherwise.
1382
 *
1383
 * The format of ipOne and ipArray are described in the comments of
1384
 * get_socket_list_from_proto() in this file.
1385
 *
1386
 * */
1387
static int match_ip_and_port(unsigned int *ipOne, unsigned int *ipArray, int sizeOf_ipArray)
1388
0
{
1389
0
  int curIPAddrIdx;
1390
0
  int curOctetIdx;
1391
0
  int ipArrayIndex;
1392
1393
  /* Loop over every IP Address */
1394
0
  for (curIPAddrIdx = 0; curIPAddrIdx < sizeOf_ipArray; curIPAddrIdx++) {
1395
1396
    /* Check for octets that don't match.  If one is found, skip the
1397
     * rest.  */
1398
0
    for (curOctetIdx = 0; curOctetIdx < NUM_IP_OCTETS + 1; curOctetIdx++) {
1399
1400
      /* We've encoded a 2D array as a 1D array.  So find out
1401
       * our position in the 1D array. */
1402
0
      ipArrayIndex =
1403
0
        curIPAddrIdx * (NUM_IP_OCTETS + 1) + curOctetIdx;
1404
1405
0
      if (ipOne[curOctetIdx] != ipArray[ipArrayIndex]) {
1406
0
        break;
1407
0
      }
1408
0
    }
1409
1410
    /* If the index from the inner loop is equal to NUM_IP_OCTETS
1411
     * + 1, then that means that every octet (and the port with the
1412
     * + 1) matched. */
1413
0
    if (curOctetIdx == NUM_IP_OCTETS + 1) {
1414
0
      return 1;
1415
0
    }
1416
1417
0
  }
1418
1419
0
  return 0;
1420
0
}
1421
1422
1423
/*
1424
 * Returns the number of bytes waiting to be consumed on the network interfaces
1425
 * assigned the IP Addresses specified in interfaceList.  The check will be
1426
 * limited to the TCP or UDP transport exclusively.  Specifically:
1427
 *
1428
 * - If forTCP is non-zero, the check involves only the TCP transport.
1429
 * - if forTCP is zero, the check involves only the UDP transport.
1430
 *
1431
 * Note: This only works on linux systems supporting the /proc/net/[tcp|udp]
1432
 *       interface.  On other systems, zero will always be returned.
1433
 */
1434
static int get_used_waiting_queue(
1435
    int forTCP, unsigned int *interfaceList, int listSize)
1436
0
{
1437
0
  FILE *fp;
1438
0
  char *fileToOpen;
1439
1440
0
  char lineBuffer[MAX_PROC_BUFFER];
1441
0
  unsigned int  ipAddress[NUM_IP_OCTETS+1];
1442
0
  int  rx_queue;
1443
0
  int  waitingQueueSize = 0;
1444
1445
0
  if (listSize==0 || interfaceList==NULL)
1446
0
    return 0;
1447
1448
  /* Set up the file we want to open. */
1449
0
  if (forTCP) {
1450
0
    fileToOpen = "/proc/net/tcp";
1451
0
  } else {
1452
0
    fileToOpen = "/proc/net/udp";
1453
0
  }
1454
1455
0
  fp = fopen(fileToOpen, "r");
1456
1457
0
  if (fp == NULL) {
1458
0
    LM_DBG("Could not open %s. openserMsgQueu eDepth and its related"
1459
0
        " alarms will not be available.\n", fileToOpen);
1460
0
    return 0;
1461
0
  }
1462
1463
  /* Read in every line of the file, parse out the ip address, port, and
1464
   * rx_queue, and compare to our list of interfaces we are listening on.
1465
   * Add up rx_queue for those lines which match our known interfaces. */
1466
0
  while (fgets(lineBuffer, MAX_PROC_BUFFER, fp)!=NULL) {
1467
1468
    /* Parse out the ip address, port, and rx_queue. */
1469
0
    if(parse_proc_net_line(lineBuffer, ipAddress, &rx_queue)) {
1470
1471
      /* Only add rx_queue if the line just parsed corresponds
1472
       * to an interface we are listening on.  We do this
1473
       * check because it is possible that this system has
1474
       * other network interfaces that OpenSER has been told
1475
       * to ignore. */
1476
0
      if (match_ip_and_port(ipAddress, interfaceList, listSize)) {
1477
0
        waitingQueueSize += rx_queue;
1478
0
      }
1479
0
    }
1480
0
  }
1481
1482
0
  fclose(fp);
1483
1484
0
  return waitingQueueSize;
1485
0
}
1486
1487
/*
1488
 * Returns the sum of the number of bytes waiting to be consumed on all network
1489
 * interfaces and transports that OpenSIPS is listening on.
1490
 *
1491
 * Note: This currently only works on systems supporting the /proc/net/[tcp|udp]
1492
 *       interface.  On other systems, zero will always be returned.  To change
1493
 *       this in the future, add an equivalent for get_used_waiting_queue().
1494
 */
1495
int get_total_bytes_waiting(int only_proto)
1496
0
{
1497
0
  static unsigned int *UDPList  = NULL;
1498
0
  static unsigned int *TCPList  = NULL;
1499
0
  static unsigned int *TLSList  = NULL;
1500
1501
0
  static int numUDPSockets  = -1;
1502
0
  static int numTCPSockets  = -1;
1503
0
  static int numTLSSockets  = -1;
1504
1505
0
  int bytesWaiting = 0;
1506
1507
  /* Extract out the IP address address for UDP, TCP, and TLS, keeping
1508
   * track of the number of IP addresses from each transport  */
1509
0
  if (numUDPSockets==-1)
1510
0
    numUDPSockets  = get_socket_list_from_proto(&UDPList,  PROTO_UDP);
1511
0
  if (numTCPSockets==-1)
1512
0
    numTCPSockets  = get_socket_list_from_proto(&TCPList,  PROTO_TCP);
1513
0
  if (numTLSSockets==-1)
1514
0
    numTLSSockets  = get_socket_list_from_proto(&TLSList,  PROTO_TLS);
1515
1516
  /* Find out the number of bytes waiting on our interface list over all
1517
   * UDP and TCP transports. */
1518
0
  if (only_proto==PROTO_NONE) {
1519
0
    bytesWaiting  += get_used_waiting_queue(0, UDPList,  numUDPSockets);
1520
0
    bytesWaiting  += get_used_waiting_queue(1, TCPList,  numTCPSockets);
1521
0
    bytesWaiting  += get_used_waiting_queue(1, TLSList,  numTLSSockets);
1522
0
  } else if (only_proto==PROTO_UDP) {
1523
0
    bytesWaiting  += get_used_waiting_queue(0, UDPList,  numUDPSockets);
1524
0
  } else if (only_proto==PROTO_TCP) {
1525
0
    bytesWaiting  += get_used_waiting_queue(1, TCPList,  numTCPSockets);
1526
0
  } else if (only_proto==PROTO_TLS) {
1527
0
    bytesWaiting  += get_used_waiting_queue(1, TLSList,  numTLSSockets);
1528
0
  }
1529
1530
0
  return bytesWaiting;
1531
0
}
1532
1533
1534
1535
void print_aliases(void)
1536
0
{
1537
0
  struct host_alias* a;
1538
1539
0
  for(a=aliases; a; a=a->next)
1540
0
    if (a->port)
1541
0
      printf("             %s: %.*s:%d\n", get_proto_name(a->proto),
1542
0
          a->alias.len, a->alias.s, a->port);
1543
0
    else
1544
0
      printf("             %s: %.*s:*\n", get_proto_name(a->proto),
1545
0
          a->alias.len, a->alias.s);
1546
0
}
1547
1548
/*
1549
 * Arguments :
1550
 *    sock - socket to have buffer increased
1551
 *    buff_choice - 0 for receive buff, 1 for send buff
1552
 *    buff_max - max size of socket buffer we are looking for
1553
 *    buff_increment - increment nr of bytes after reaching limit
1554
 *
1555
 *  Returns :
1556
 *    0 in case of success
1557
 *    1 in case of failure
1558
*/
1559
int probe_max_sock_buff(int sock,int buff_choice,int buff_max,int buff_increment)
1560
0
{
1561
0
  unsigned int optval, ioptval, ioptvallen, foptval, foptvallen, voptval, voptvallen;
1562
0
  int phase=0;
1563
0
  int buff_opt;
1564
0
  char *info;
1565
1566
0
  if (buff_choice == 0)
1567
0
  {
1568
0
    info = "rcv";
1569
0
    buff_opt = SO_RCVBUF;
1570
0
  }
1571
0
  else if (buff_choice == 1)
1572
0
  {
1573
0
    info = "snd";
1574
0
    buff_opt = SO_SNDBUF;
1575
0
  }
1576
0
  else
1577
0
  {
1578
0
    LM_WARN("Called with unimplemented buff_choice - %d\n",buff_choice);
1579
0
    return 1;
1580
0
  }
1581
1582
  /* try to increase buffer size as much as we can */
1583
0
  ioptvallen=sizeof(ioptval);
1584
0
  if (getsockopt( sock, SOL_SOCKET, buff_opt, (void*) &ioptval,
1585
0
        &ioptvallen) == -1 )
1586
0
  {
1587
0
    LM_ERR("getsockopt: %s\n", strerror(errno));
1588
0
    return -1;
1589
0
  }
1590
0
  if ( ioptval==0 )
1591
0
  {
1592
0
    LM_DBG(" getsockopt: %s initially set to 0; resetting to %d\n",
1593
0
      info,buff_increment );
1594
0
    ioptval=buff_increment;
1595
0
  } else LM_DBG("getsockopt: %s is initially %d\n",info, ioptval );
1596
0
  for (optval=ioptval; ;  ) {
1597
    /* increase size; double in initial phase, add linearly later */
1598
0
    if (phase==0) optval <<= 1; else optval+=buff_increment;
1599
0
    if (optval > maxbuffer){
1600
0
      if (phase==1) break;
1601
0
      else { phase=1; optval >>=1; continue; }
1602
0
    }
1603
    /* LM_DBG("trying : %d\n", optval ); */
1604
0
    if (setsockopt( sock, SOL_SOCKET, buff_opt,
1605
0
      (void*)&optval, sizeof(optval)) ==-1){
1606
      /* Solaris returns -1 if asked size too big; Linux ignores */
1607
0
      LM_DBG("setsockopt: SOL_SOCKET failed"
1608
0
          " for %d, phase %d: %s\n", optval, phase, strerror(errno));
1609
      /* if setting buffer size failed and still in the aggressive
1610
         phase, try less aggressively; otherwise give up */
1611
0
      if (phase==0) { phase=1; optval >>=1 ; continue; }
1612
0
      else break;
1613
0
    }
1614
    /* verify if change has taken effect */
1615
    /* Linux note -- otherwise I would never know that; funny thing: Linux
1616
       doubles size for which we asked in setsockopt */
1617
0
    voptvallen=sizeof(voptval);
1618
0
    if (getsockopt( sock, SOL_SOCKET, buff_opt, (void*) &voptval,
1619
0
        &voptvallen) == -1 )
1620
0
    {
1621
0
      LM_ERR("getsockopt: %s\n", strerror(errno));
1622
0
      return -1;
1623
0
    } else {
1624
      /*LM_DBG("setting %s: set=%d,verify=%d\n",info,
1625
        optval, voptval);*/
1626
0
      if (voptval<optval) {
1627
0
        LM_DBG("setting %s buf to %d had no effect\n",info,optval);
1628
        /* if setting buffer size failed and still in the aggressive
1629
        phase, try less aggressively; otherwise give up */
1630
0
        if (phase==0) { phase=1; optval >>=1 ; continue; }
1631
0
        else break;
1632
0
      }
1633
0
    }
1634
1635
0
  } /* for ... */
1636
0
  foptvallen=sizeof(foptval);
1637
0
  if (getsockopt( sock, SOL_SOCKET, buff_opt, (void*) &foptval,
1638
0
        &foptvallen) == -1 )
1639
0
  {
1640
0
    LM_ERR("getsockopt: %s\n", strerror(errno));
1641
0
    return -1;
1642
0
  }
1643
0
  LM_DBG("using %s buffer of %d kb\n",info, (foptval/1024));
1644
1645
0
  return 0;
1646
0
}
1647
1648
struct socket_id *socket_info2id(struct socket_info *si)
1649
0
{
1650
0
  static struct socket_id sid;
1651
1652
0
  memset(&sid, 0, sizeof sid);
1653
0
  sid.name = si->name.s;
1654
0
  sid.adv_name = si->adv_sock_str.s;
1655
0
  sid.tag = si->tag.s;
1656
0
  if (si->s_profile)
1657
0
    sid.auto_scaling_profile = si->s_profile->name;
1658
0
  sid.adv_port = si->adv_port;
1659
0
  sid.proto = si->proto;
1660
0
  sid.port = si->port_no;
1661
0
  sid.workers = si->workers;
1662
0
  return &sid;
1663
0
}