Coverage Report

Created: 2026-08-31 06:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rtpproxy/src/rtpp_controlfd.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2004-2006 Maxim Sobolev <sobomax@FreeBSD.org>
3
 * Copyright (c) 2006-2014 Sippy Software, Inc., http://www.sippysoft.com
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 *
15
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
 * SUCH DAMAGE.
26
 *
27
 */
28
29
#include <sys/types.h>
30
#include <sys/socket.h>
31
#include <sys/stat.h>
32
#include <sys/un.h>
33
#include <netinet/in.h>
34
#include <errno.h>
35
#include <fcntl.h>
36
#include <stdio.h>
37
#include <string.h>
38
#include <stdlib.h>
39
#include <unistd.h>
40
41
#include "config_pp.h"
42
43
#include "rtpp_types.h"
44
#include "rtpp_defines.h"
45
#include "rtpp_list.h"
46
#include "rtpp_log.h"
47
#include "rtpp_log_obj.h"
48
#include "rtpp_cfg.h"
49
#include "rtpp_command.h"
50
#include "rtpp_controlfd.h"
51
#include "rtpp_mallocs.h"
52
#include "rtpp_network.h"
53
#include "rtpp_runcreds.h"
54
#include "rtpp_util.h"
55
56
#if !defined(NO_ERR_H)
57
#include <err.h>
58
#endif
59
60
#ifdef HAVE_SYSTEMD_DAEMON
61
#include <systemd/sd-daemon.h>
62
#endif
63
64
static int
65
controlfd_init_systemd(void)
66
0
{
67
#ifdef HAVE_SYSTEMD_DAEMON
68
    int nfd;
69
70
    nfd = sd_listen_fds(0);
71
    if (nfd > 1) {
72
        warnx("Too many file descriptors received.");
73
        return (-1);
74
    }
75
    if (nfd == 1) {
76
        return (SD_LISTEN_FDS_START + 0);
77
    }
78
#else
79
0
    warnx("systemd is not supported or not detected on your system, "
80
0
      "please consider filing report or submitting a patch");
81
0
#endif
82
0
    return (-1);
83
0
}
84
85
static int
86
controlfd_init_ifsun(const struct rtpp_cfg *cfsp, struct rtpp_ctrl_sock *csp)
87
0
{
88
0
    int controlfd, reuse;
89
0
    struct sockaddr_un *ifsun;
90
91
0
    if (strlen(csp->cmd_sock) >= sizeof(ifsun->sun_path)) {
92
0
        warnx("socket name is too long: %s", csp->cmd_sock);
93
0
        errno = ENAMETOOLONG;
94
0
        return (-1);
95
0
    }
96
0
    unlink(csp->cmd_sock);
97
0
    ifsun = sstosun(&csp->bindaddr);
98
0
    memset(ifsun, '\0', sizeof(struct sockaddr_un));
99
#if defined(HAVE_SOCKADDR_SUN_LEN)
100
    ifsun->sun_len = strlen(csp->cmd_sock);
101
#endif
102
0
    ifsun->sun_family = AF_LOCAL;
103
0
    strlcpy(ifsun->sun_path, csp->cmd_sock, sizeof(ifsun->sun_path));
104
0
    controlfd = socket(AF_LOCAL, SOCK_STREAM, 0);
105
0
    if (controlfd == -1) {
106
0
        warn("can't create socket");
107
0
        return (-1);
108
0
    }
109
0
    reuse = 1;
110
0
    setsockopt(controlfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
111
0
    if (bind(controlfd, sstosa(ifsun), sizeof(struct sockaddr_un)) < 0) {
112
0
        warn("can't bind to a socket: %s", csp->cmd_sock);
113
0
        goto e0;
114
0
    }
115
0
    if ((cfsp->runcreds->uname != NULL || cfsp->runcreds->gname != NULL) &&
116
0
      chown(csp->cmd_sock, cfsp->runcreds->uid, cfsp->runcreds->gid) == -1) {
117
0
        warn("can't set owner of the socket: %s", csp->cmd_sock);
118
0
        goto e0;
119
0
    }
120
0
    if ((cfsp->runcreds->gname != NULL) && cfsp->runcreds->sock_mode != 0 &&
121
0
      (chmod(csp->cmd_sock, cfsp->runcreds->sock_mode) == -1)) {
122
0
        warn("can't allow rw acces to group");
123
0
        goto e0;
124
0
    }
125
0
    if (listen(controlfd, 32) != 0) {
126
0
        warn("can't listen on a socket: %s", csp->cmd_sock);
127
0
        goto e0;
128
0
    }
129
130
0
    return (controlfd);
131
0
e0:
132
0
    close(controlfd);
133
0
    return (-1);
134
0
}
135
136
static int
137
controlfd_setbindhost(const struct rtpp_cfg *cfsp, struct rtpp_ctrl_sock *csp,
138
  struct sockaddr *ifsin, int af)
139
0
{
140
0
    const char *cp, *bindhost, *port;
141
0
    char *bindhost_buf;
142
0
    size_t bindhost_len;
143
0
    int r;
144
145
0
    cp = strrchr(csp->cmd_sock, ':');
146
0
    if (cp != NULL) {
147
0
        bindhost_len = cp - csp->cmd_sock;
148
0
        bindhost_buf = alloca(bindhost_len + 1);
149
0
        memcpy(bindhost_buf, csp->cmd_sock, bindhost_len);
150
0
        bindhost_buf[bindhost_len] = '\0';
151
0
        bindhost = bindhost_buf;
152
0
        port = cp + 1;
153
0
    } else {
154
0
        bindhost = csp->cmd_sock;
155
0
        port = CPORT;
156
0
    }
157
0
    if (*port == '\0')
158
0
        port = CPORT;
159
0
    csp->port_ctl = atoi(port);
160
0
    r = setbindhost(ifsin, af, bindhost, port, cfsp->no_resolve);
161
0
    if (r != 0) {
162
0
        warnx("setbindhost failed");
163
0
        return (-1);
164
0
    }
165
0
    return (0);
166
0
}
167
168
static int
169
controlfd_init_udp(const struct rtpp_cfg *cfsp, struct rtpp_ctrl_sock *csp)
170
0
{
171
0
    struct sockaddr *ifsin;
172
0
    int controlfd, so_rcvbuf, i, r;
173
174
0
    i = (csp->type == RTPC_UDP6) ? AF_INET6 : AF_INET;
175
0
    ifsin = sstosa(&csp->bindaddr);
176
0
    r = controlfd_setbindhost(cfsp, csp, ifsin, i);
177
0
    if (r != 0) {
178
0
        return (-1);
179
0
    }
180
0
    controlfd = socket(i, SOCK_DGRAM, 0);
181
0
    if (controlfd == -1) {
182
0
        warn("can't create socket");
183
0
        return (-1);
184
0
    }
185
0
    so_rcvbuf = 16 * 1024;
186
0
    if (setsockopt(controlfd, SOL_SOCKET, SO_RCVBUF, &so_rcvbuf, sizeof(so_rcvbuf)) == -1)
187
0
        RTPP_ELOG(cfsp->glog, RTPP_LOG_ERR, "unable to set 16K receive buffer size on controlfd");
188
0
    if (bind(controlfd, ifsin, SA_LEN(ifsin)) < 0) {
189
0
        warn("can't bind to a socket: %s", csp->cmd_sock);
190
0
        close(controlfd);
191
0
        return (-1);
192
0
    }
193
194
0
    return (controlfd);
195
0
}
196
197
static int
198
controlfd_init_tcp(const struct rtpp_cfg *cfsp, struct rtpp_ctrl_sock *csp)
199
0
{
200
0
    struct sockaddr *ifsin;
201
0
    int controlfd, so_rcvbuf, i, r;
202
203
0
    i = (csp->type == RTPC_TCP6) ? AF_INET6 : AF_INET;
204
0
    ifsin = sstosa(&csp->bindaddr);
205
0
    r = controlfd_setbindhost(cfsp, csp, ifsin, i);
206
0
    if (r != 0) {
207
0
        return (-1);
208
0
    }
209
0
    controlfd = socket(i, SOCK_STREAM, 0);
210
0
    if (controlfd == -1) {
211
0
        warn("can't create socket");
212
0
        return (-1);
213
0
    }
214
0
    so_rcvbuf = 16 * 1024;
215
0
    if (setsockopt(controlfd, SOL_SOCKET, SO_RCVBUF, &so_rcvbuf, sizeof(so_rcvbuf)) == -1)
216
0
        RTPP_ELOG(cfsp->glog, RTPP_LOG_ERR, "unable to set 16K receive buffer size on controlfd");
217
0
    if (bind(controlfd, ifsin, SA_LEN(ifsin)) < 0) {
218
0
        warn("can't bind to a socket: %s", csp->cmd_sock);
219
0
        goto e0;
220
0
    }
221
0
    if (listen(controlfd, 32) != 0) {
222
0
        warn("can't listen on a socket: %s", csp->cmd_sock);
223
0
        goto e0;
224
0
    }
225
226
0
    return (controlfd);
227
0
e0:
228
0
    close(controlfd);
229
0
    return (-1);
230
0
}
231
232
int
233
rtpp_controlfd_init(const struct rtpp_cfg *cfsp)
234
0
{
235
0
    int controlfd_in, controlfd_out, flags;
236
0
    struct rtpp_ctrl_sock *ctrl_sock;
237
238
0
    for (ctrl_sock = RTPP_LIST_HEAD(cfsp->ctrl_socks);
239
0
      ctrl_sock != NULL; ctrl_sock = RTPP_ITER_NEXT(ctrl_sock)) {
240
0
        switch (ctrl_sock->type) {
241
0
        case RTPC_SYSD:
242
0
            controlfd_in = controlfd_out = controlfd_init_systemd();
243
0
            break;
244
245
0
        case RTPC_IFSUN:
246
0
        case RTPC_IFSUN_C:
247
0
            controlfd_in = controlfd_out = controlfd_init_ifsun(cfsp, ctrl_sock);
248
0
            break;
249
250
0
        case RTPC_UDP4:
251
0
        case RTPC_UDP6:
252
0
            controlfd_in = controlfd_out = controlfd_init_udp(cfsp, ctrl_sock);
253
0
            break;
254
255
0
        case RTPC_TCP4:
256
0
        case RTPC_TCP6:
257
0
            controlfd_in = controlfd_out = controlfd_init_tcp(cfsp, ctrl_sock);
258
0
            break;
259
260
0
        case RTPC_STDIO:
261
0
            controlfd_in = fileno(stdin);
262
0
            controlfd_out = fileno(stdout);
263
0
            break;
264
265
0
        case RTPC_FD:
266
0
            if (atoi_safe(ctrl_sock->cmd_sock, &controlfd_in) != ATOI_OK ||
267
0
              controlfd_in < 0) {
268
0
                warnx("invalid fd: %s", ctrl_sock->cmd_sock);
269
0
                return (-1);
270
0
            }
271
0
            controlfd_out = controlfd_in;
272
0
            break;
273
0
        default:
274
0
            warnx("unhandled RTPC_XXX type: %d", ctrl_sock->type);
275
0
            abort();
276
0
        }
277
0
        if (controlfd_in < 0 || controlfd_out < 0) {
278
0
            return (-1);
279
0
        }
280
0
        ctrl_sock->controlfd_in = controlfd_in;
281
0
        ctrl_sock->controlfd_out = controlfd_out;
282
0
        flags = fcntl(controlfd_in, F_GETFL);
283
0
        if (flags < 0 || fcntl(controlfd_in, F_SETFL, flags | O_NONBLOCK) < 0) {
284
0
            warn("can't set O_NONBLOCK on a socket: %d", controlfd_in);
285
0
            return (-1);
286
0
        }
287
0
    }
288
289
0
    return (0);
290
0
}
291
292
socklen_t
293
rtpp_csock_addrlen(struct rtpp_ctrl_sock *ctrl_sock)
294
0
{
295
296
0
    switch (ctrl_sock->type) {
297
0
    case RTPC_IFSUN:
298
0
    case RTPC_IFSUN_C:
299
0
        return (sizeof(struct sockaddr_un));
300
301
0
    case RTPC_UDP4:
302
0
    case RTPC_TCP4:
303
0
        return (sizeof(struct sockaddr_in));
304
305
0
    case RTPC_UDP6:
306
0
    case RTPC_TCP6:
307
0
        return (sizeof(struct sockaddr_in6));
308
            
309
0
    case RTPC_SYSD:
310
0
        return (sizeof(struct sockaddr_un));
311
            
312
0
    default:
313
0
        break;
314
0
    }
315
316
0
    return (0);
317
0
}
318
319
void
320
rtpp_controlfd_cleanup(const struct rtpp_cfg *cfsp)
321
0
{
322
0
    struct rtpp_ctrl_sock *ctrl_sock;
323
324
0
    for (ctrl_sock = RTPP_LIST_HEAD(cfsp->ctrl_socks);
325
0
      ctrl_sock != NULL; ctrl_sock = RTPP_ITER_NEXT(ctrl_sock)) {
326
0
        if (RTPP_CTRL_ISUNIX(ctrl_sock) == 0)
327
0
            continue;
328
0
        unlink(ctrl_sock->cmd_sock);
329
0
    }
330
0
}
331
332
struct rtpp_ctrl_sock *
333
rtpp_ctrl_sock_parse(const char *optarg)
334
0
{
335
0
    struct rtpp_ctrl_sock *rcsp;
336
337
0
    rcsp = rtpp_zmalloc(sizeof(struct rtpp_ctrl_sock));
338
0
    if (rcsp == NULL) {
339
0
        return (NULL);
340
0
    }
341
0
    rcsp->type= RTPC_IFSUN;
342
0
    if (strncmp("udp:", optarg, 4) == 0) {
343
0
        rcsp->type= RTPC_UDP4;
344
0
        optarg += 4;
345
0
    } else if (strncmp("udp6:", optarg, 5) == 0) {
346
0
        rcsp->type= RTPC_UDP6;
347
0
        optarg += 5;
348
0
    } else if (strncmp("unix:", optarg, 5) == 0) {
349
0
        rcsp->type= RTPC_IFSUN;
350
0
        optarg += 5;
351
0
    } else if (strncmp("cunix:", optarg, 6) == 0) {
352
0
        rcsp->type= RTPC_IFSUN_C;
353
0
        optarg += 6;
354
0
    } else if (strncmp("systemd:", optarg, 8) == 0) {
355
0
        rcsp->type= RTPC_SYSD;
356
0
        optarg += 8;
357
0
    } else if (strncmp("stdio:", optarg, 6) == 0) {
358
0
        rcsp->type= RTPC_STDIO;
359
0
        optarg += 6;
360
0
    } else if (strncmp("stdioc:", optarg, 7) == 0) {
361
0
        rcsp->type= RTPC_STDIO;
362
0
        rcsp->exit_on_close = 1;
363
0
        optarg += 7;
364
0
    } else if (rtpp_is_lib && strncmp("fd:", optarg, 3) == 0) {
365
0
        rcsp->type= RTPC_FD;
366
0
        optarg += 3;
367
0
    } else if (strncmp("tcp:", optarg, 4) == 0) {
368
0
        rcsp->type= RTPC_TCP4;
369
0
        optarg += 4;
370
0
    } else if (strncmp("tcp6:", optarg, 5) == 0) {
371
0
        rcsp->type= RTPC_TCP6;
372
0
        optarg += 5;
373
0
    }
374
0
    rcsp->cmd_sock = optarg;
375
376
0
    return (rcsp);
377
0
}
378
379
#if 0
380
const char *
381
rtpp_ctrl_sock_describe(struct rtpp_ctrl_sock *rcsp)
382
{
383
384
    switch (rcsp->type) {
385
    case RTPC_IFSUN:
386
        return "unix";
387
388
    case RTPC_UDP4:
389
        return "udp";
390
391
    case RTPC_UDP6:
392
        return "udp6";
393
394
    case RTPC_IFSUN_C:
395
        return "cunix";
396
397
    case RTPC_SYSD:
398
        return "systemd";
399
400
    case RTPC_STDIO:
401
        return "stdio";
402
403
    case RTPC_TCP4:
404
        return "tcp";
405
406
    case RTPC_TCP6:
407
        return "tcp6";
408
409
    default:
410
        abort();
411
    }
412
}
413
#endif