Coverage Report

Created: 2025-11-11 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open5gs/lib/core/ogs-socknode.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
3
 *
4
 * This file is part of Open5GS.
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU Affero General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program 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, see <https://www.gnu.org/licenses/>.
18
 */
19
20
#include "core-config-private.h"
21
22
#if HAVE_NET_IF_H
23
#include <net/if.h>
24
#endif
25
26
#if HAVE_IFADDRS_H
27
#include <ifaddrs.h>
28
#endif
29
30
#include "ogs-core.h"
31
32
#undef OGS_LOG_DOMAIN
33
0
#define OGS_LOG_DOMAIN __ogs_sock_domain
34
35
ogs_socknode_t *ogs_socknode_new(ogs_sockaddr_t *addr)
36
0
{
37
0
    ogs_socknode_t *node = NULL;
38
39
0
    ogs_assert(addr);
40
41
0
    node = ogs_calloc(1, sizeof(ogs_socknode_t));
42
0
    if (!node) {
43
0
        ogs_error("ogs_calloc() failed");
44
0
        return NULL;
45
0
    }
46
47
0
    node->addr = addr;
48
49
0
    return node;
50
0
}
51
52
void ogs_socknode_free(ogs_socknode_t *node)
53
0
{
54
0
    ogs_assert(node);
55
56
0
    ogs_freeaddrinfo(node->addr);
57
0
    if (node->dev)
58
0
        ogs_free(node->dev);
59
0
    if (node->poll)
60
0
        ogs_pollset_remove(node->poll);
61
0
    if (node->sock) {
62
0
        if (node->cleanup)
63
0
            node->cleanup(node->sock);
64
0
        else
65
0
            ogs_sock_destroy(node->sock);
66
0
    }
67
0
    if (node->option)
68
0
        ogs_free(node->option);
69
0
    ogs_free(node);
70
0
}
71
72
ogs_socknode_t *ogs_socknode_add(ogs_list_t *list,
73
        int family, ogs_sockaddr_t *addr, ogs_sockopt_t *option)
74
0
{
75
0
    ogs_socknode_t *node = NULL;
76
0
    ogs_sockaddr_t *dup = NULL;
77
78
0
    ogs_assert(list);
79
0
    ogs_assert(addr);
80
81
0
    ogs_assert(OGS_OK == ogs_copyaddrinfo(&dup, addr));
82
0
    if (family != AF_UNSPEC)
83
0
        ogs_filteraddrinfo(&dup, family);
84
85
0
    if (dup) {
86
0
        node = ogs_socknode_new(dup);
87
0
        ogs_assert(node);
88
0
        ogs_list_add(list, node);
89
90
0
        if (option)
91
0
            node->option = ogs_memdup(option, sizeof *option);
92
0
    }
93
94
0
    return node;
95
0
}
96
97
void ogs_socknode_remove(ogs_list_t *list, ogs_socknode_t *node)
98
0
{
99
0
    ogs_assert(node);
100
101
0
    ogs_list_remove(list, node);
102
0
    ogs_socknode_free(node);
103
0
}
104
105
void ogs_socknode_remove_all(ogs_list_t *list)
106
0
{
107
0
    ogs_socknode_t *node = NULL, *saved_node = NULL;
108
109
0
    ogs_list_for_each_safe(list, saved_node, node)
110
0
        ogs_socknode_remove(list, node);
111
0
}
112
113
int ogs_socknode_probe(ogs_list_t *list, ogs_list_t *list6,
114
        const char *dev, uint16_t port, ogs_sockopt_t *option)
115
0
{
116
0
#if defined(HAVE_GETIFADDRS)
117
0
    ogs_socknode_t *node = NULL;
118
0
    struct ifaddrs *iflist, *cur;
119
0
    int rc;
120
121
0
    rc = getifaddrs(&iflist);
122
0
    if (rc != 0) {
123
0
        ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, "getifaddrs failed");
124
0
        return OGS_ERROR;
125
0
    }
126
127
0
    for (cur = iflist; cur != NULL; cur = cur->ifa_next) {
128
0
        ogs_sockaddr_t *addr = NULL;
129
130
0
        if (cur->ifa_flags & IFF_LOOPBACK)
131
0
            continue;
132
133
0
        if (cur->ifa_flags & IFF_POINTOPOINT)
134
0
            continue;
135
136
0
        if (cur->ifa_addr == NULL) /* may happen with ppp interfaces */
137
0
            continue;
138
139
0
        if (dev && strcmp(dev, cur->ifa_name) != 0)
140
0
            continue;
141
142
0
        addr = (ogs_sockaddr_t *)cur->ifa_addr;
143
0
        if (cur->ifa_addr->sa_family == AF_INET) {
144
0
            if (!list) continue;
145
146
0
#ifndef IN_IS_ADDR_LOOPBACK
147
0
#define IN_IS_ADDR_LOOPBACK(a) \
148
0
  ((((long int) (a)->s_addr) & be32toh(0xff000000)) == be32toh(0x7f000000))
149
0
#endif /* IN_IS_ADDR_LOOPBACK */
150
151
/* An IP equivalent to IN6_IS_ADDR_UNSPECIFIED */
152
0
#ifndef IN_IS_ADDR_UNSPECIFIED
153
0
#define IN_IS_ADDR_UNSPECIFIED(a) \
154
0
  (((long int) (a)->s_addr) == 0x00000000)
155
0
#endif /* IN_IS_ADDR_UNSPECIFIED */
156
0
            if (IN_IS_ADDR_UNSPECIFIED(&addr->sin.sin_addr) ||
157
0
                IN_IS_ADDR_LOOPBACK(&addr->sin.sin_addr))
158
0
                continue;
159
0
        } else if (cur->ifa_addr->sa_family == AF_INET6) {
160
0
            if (!list6) continue;
161
162
0
            if (IN6_IS_ADDR_UNSPECIFIED(&addr->sin6.sin6_addr) ||
163
0
                IN6_IS_ADDR_LOOPBACK(&addr->sin6.sin6_addr) ||
164
0
                IN6_IS_ADDR_MULTICAST(&addr->sin6.sin6_addr) ||
165
0
                IN6_IS_ADDR_LINKLOCAL(&addr->sin6.sin6_addr) ||
166
0
                IN6_IS_ADDR_SITELOCAL(&addr->sin6.sin6_addr))
167
0
                continue;
168
0
        } else
169
0
            continue;
170
171
0
        addr = ogs_calloc(1, sizeof(ogs_sockaddr_t));
172
0
        memcpy(&addr->sa, cur->ifa_addr, ogs_sockaddr_len(cur->ifa_addr));
173
0
        addr->ogs_sin_port = htobe16(port);
174
175
0
        node = ogs_calloc(1, sizeof(ogs_socknode_t));
176
0
        node->addr = addr;
177
0
        if (dev)
178
0
            node->dev = ogs_strdup(dev);
179
180
0
        if (addr->ogs_sa_family == AF_INET) {
181
0
            ogs_assert(list);
182
0
            ogs_list_add(list, node);
183
0
        } else if (addr->ogs_sa_family == AF_INET6) {
184
0
            ogs_assert(list6);
185
0
            ogs_list_add(list6, node);
186
0
        } else
187
0
            ogs_assert_if_reached();
188
189
0
        if (option)
190
0
            node->option = ogs_memdup(option, sizeof *option);
191
0
    }
192
193
0
    freeifaddrs(iflist);
194
0
    return OGS_OK;
195
#elif defined(_WIN32)
196
    return OGS_OK;
197
#else
198
    ogs_assert_if_reached();
199
    return OGS_ERROR;
200
#endif
201
202
0
}
203
204
#if 0 /* deprecated */
205
int ogs_socknode_fill_scope_id_in_local(ogs_sockaddr_t *sa_list)
206
{
207
#if defined(HAVE_GETIFADDRS)
208
    struct ifaddrs *iflist = NULL, *cur;
209
    int rc;
210
    ogs_sockaddr_t *addr, *ifaddr;
211
212
    for (addr = sa_list; addr != NULL; addr = addr->next) {
213
        if (addr->ogs_sa_family != AF_INET6)
214
            continue;
215
216
        if (!IN6_IS_ADDR_LINKLOCAL(&addr->sin6.sin6_addr))
217
            continue;
218
219
        if (addr->sin6.sin6_scope_id != 0)
220
            continue;
221
222
        if (iflist == NULL) {
223
            rc = getifaddrs(&iflist);
224
            if (rc != 0) {
225
                ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
226
                        "getifaddrs failed");
227
                return OGS_ERROR;
228
            }
229
        }
230
231
        for (cur = iflist; cur != NULL; cur = cur->ifa_next) {
232
            ifaddr = (ogs_sockaddr_t *)cur->ifa_addr;
233
234
            if (cur->ifa_addr == NULL) /* may happen with ppp interfaces */
235
                continue;
236
237
            if (cur->ifa_addr->sa_family != AF_INET6)
238
                continue;
239
240
            if (!IN6_IS_ADDR_LINKLOCAL(&ifaddr->sin6.sin6_addr))
241
                continue;
242
243
            if (memcmp(&addr->sin6.sin6_addr,
244
                    &ifaddr->sin6.sin6_addr, sizeof(struct in6_addr)) == 0) {
245
                /* Fill Scope ID in localhost */
246
                addr->sin6.sin6_scope_id = ifaddr->sin6.sin6_scope_id;
247
            }
248
        }
249
    }
250
251
    if (iflist)
252
        freeifaddrs(iflist);
253
254
    return OGS_OK;
255
#elif defined(_WIN32)
256
    return OGS_OK;
257
#else
258
    ogs_assert_if_reached();
259
    return OGS_ERROR;
260
#endif
261
}
262
#endif
263
264
void ogs_socknode_set_cleanup(
265
        ogs_socknode_t *node, void (*cleanup)(ogs_sock_t *))
266
0
{
267
0
    ogs_assert(node);
268
0
    ogs_assert(cleanup);
269
270
0
    node->cleanup = cleanup;
271
0
}
272
273
ogs_sock_t *ogs_socknode_sock_first(ogs_list_t *list)
274
0
{
275
0
    ogs_socknode_t *snode = NULL;
276
277
0
    ogs_assert(list);
278
0
    ogs_list_for_each(list, snode) {
279
0
        if (snode->sock)
280
0
            return snode->sock;
281
0
    }
282
283
0
    return NULL;
284
0
}