Coverage Report

Created: 2025-08-24 06:53

/src/rtpproxy/src/rtpp_controlfd.c
Line
Count
Source (jump to first uncovered line)
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, controlfd;
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_init_udp(const struct rtpp_cfg *cfsp, struct rtpp_ctrl_sock *csp)
138
0
{
139
0
    struct sockaddr *ifsin;
140
0
    char *cp, *tcp = NULL;
141
0
    int controlfd, so_rcvbuf, i, r;
142
143
0
    cp = strrchr(csp->cmd_sock, ':');
144
0
    if (cp != NULL) {
145
0
        *cp = '\0';
146
0
        tcp = cp;
147
0
        cp++;
148
0
    }
149
0
    if (cp == NULL || *cp == '\0')
150
0
        cp = CPORT;
151
0
    csp->port_ctl = atoi(cp);
152
0
    i = (csp->type == RTPC_UDP6) ? AF_INET6 : AF_INET;
153
0
    ifsin = sstosa(&csp->bindaddr);
154
0
    r = setbindhost(ifsin, i, csp->cmd_sock, cp, cfsp->no_resolve);
155
0
    if (tcp != NULL)
156
0
        *tcp = ':';
157
0
    if (r != 0) {
158
0
        warnx("setbindhost failed");
159
0
        return (-1);
160
0
    }
161
0
    controlfd = socket(i, SOCK_DGRAM, 0);
162
0
    if (controlfd == -1) {
163
0
        warn("can't create socket");
164
0
        return (-1);
165
0
    }
166
0
    so_rcvbuf = 16 * 1024;
167
0
    if (setsockopt(controlfd, SOL_SOCKET, SO_RCVBUF, &so_rcvbuf, sizeof(so_rcvbuf)) == -1)
168
0
        RTPP_ELOG(cfsp->glog, RTPP_LOG_ERR, "unable to set 16K receive buffer size on controlfd");
169
0
    if (bind(controlfd, ifsin, SA_LEN(ifsin)) < 0) {
170
0
        warn("can't bind to a socket: %s", csp->cmd_sock);
171
0
        close(controlfd);
172
0
        return (-1);
173
0
    }
174
175
0
    return (controlfd);
176
0
}
177
178
static int
179
controlfd_init_tcp(const struct rtpp_cfg *cfsp, struct rtpp_ctrl_sock *csp)
180
0
{
181
0
    struct sockaddr *ifsin;
182
0
    char *cp, *tcp = NULL;;
183
0
    int controlfd, so_rcvbuf, i, r;
184
185
0
    cp = strrchr(csp->cmd_sock, ':');
186
0
    if (cp != NULL) {
187
0
        *cp = '\0';
188
0
        tcp = cp;
189
0
        cp++;
190
0
    }
191
0
    if (cp == NULL || *cp == '\0')
192
0
        cp = CPORT;
193
0
    csp->port_ctl = atoi(cp);
194
0
    i = (csp->type == RTPC_TCP6) ? AF_INET6 : AF_INET;
195
0
    ifsin = sstosa(&csp->bindaddr);
196
0
    r = setbindhost(ifsin, i, csp->cmd_sock, cp, cfsp->no_resolve);
197
0
    if (tcp != NULL)
198
0
        *tcp = ':';
199
0
    if (r != 0) {
200
0
        warnx("setbindhost failed");
201
0
        return (-1);
202
0
    }
203
0
    controlfd = socket(i, SOCK_STREAM, 0);
204
0
    if (controlfd == -1) {
205
0
        warn("can't create socket");
206
0
        return (-1);
207
0
    }
208
0
    so_rcvbuf = 16 * 1024;
209
0
    if (setsockopt(controlfd, SOL_SOCKET, SO_RCVBUF, &so_rcvbuf, sizeof(so_rcvbuf)) == -1)
210
0
        RTPP_ELOG(cfsp->glog, RTPP_LOG_ERR, "unable to set 16K receive buffer size on controlfd");
211
0
    if (bind(controlfd, ifsin, SA_LEN(ifsin)) < 0) {
212
0
        warn("can't bind to a socket: %s", csp->cmd_sock);
213
0
        goto e0;
214
0
    }
215
0
    if (listen(controlfd, 32) != 0) {
216
0
        warn("can't listen on a socket: %s", csp->cmd_sock);
217
0
        goto e0;
218
0
    }
219
220
0
    return (controlfd);
221
0
e0:
222
0
    close(controlfd);
223
0
    return (-1);
224
0
}
225
226
int
227
rtpp_controlfd_init(const struct rtpp_cfg *cfsp)
228
0
{
229
0
    int controlfd_in, controlfd_out, flags;
230
0
    struct rtpp_ctrl_sock *ctrl_sock;
231
232
0
    for (ctrl_sock = RTPP_LIST_HEAD(cfsp->ctrl_socks);
233
0
      ctrl_sock != NULL; ctrl_sock = RTPP_ITER_NEXT(ctrl_sock)) {
234
0
        switch (ctrl_sock->type) {
235
0
        case RTPC_SYSD:
236
0
            controlfd_in = controlfd_out = controlfd_init_systemd();
237
0
            break;
238
239
0
        case RTPC_IFSUN:
240
0
        case RTPC_IFSUN_C:
241
0
            controlfd_in = controlfd_out = controlfd_init_ifsun(cfsp, ctrl_sock);
242
0
            break;
243
244
0
        case RTPC_UDP4:
245
0
        case RTPC_UDP6:
246
0
            controlfd_in = controlfd_out = controlfd_init_udp(cfsp, ctrl_sock);
247
0
            break;
248
249
0
        case RTPC_TCP4:
250
0
        case RTPC_TCP6:
251
0
            controlfd_in = controlfd_out = controlfd_init_tcp(cfsp, ctrl_sock);
252
0
            break;
253
254
0
        case RTPC_STDIO:
255
0
            controlfd_in = fileno(stdin);
256
0
            controlfd_out = fileno(stdout);
257
0
            break;
258
259
0
        case RTPC_FD:
260
0
            if (atoi_safe(ctrl_sock->cmd_sock, &controlfd_in) != ATOI_OK ||
261
0
              controlfd_in < 0) {
262
0
                warnx("invalid fd: %s", ctrl_sock->cmd_sock);
263
0
                return (-1);
264
0
            }
265
0
            controlfd_out = controlfd_in;
266
0
            break;
267
0
        }
268
0
        if (controlfd_in < 0 || controlfd_out < 0) {
269
0
            return (-1);
270
0
        }
271
0
        ctrl_sock->controlfd_in = controlfd_in;
272
0
        ctrl_sock->controlfd_out = controlfd_out;
273
0
        flags = fcntl(controlfd_in, F_GETFL);
274
0
        if (flags < 0 || fcntl(controlfd_in, F_SETFL, flags | O_NONBLOCK) < 0) {
275
0
            warn("can't set O_NONBLOCK on a socket: %d", controlfd_in);
276
0
            return (-1);
277
0
        }
278
0
    }
279
280
0
    return (0);
281
0
}
282
283
socklen_t
284
rtpp_csock_addrlen(struct rtpp_ctrl_sock *ctrl_sock)
285
0
{
286
287
0
    switch (ctrl_sock->type) {
288
0
    case RTPC_IFSUN:
289
0
    case RTPC_IFSUN_C:
290
0
        return (sizeof(struct sockaddr_un));
291
292
0
    case RTPC_UDP4:
293
0
    case RTPC_TCP4:
294
0
        return (sizeof(struct sockaddr_in));
295
296
0
    case RTPC_UDP6:
297
0
    case RTPC_TCP6:
298
0
        return (sizeof(struct sockaddr_in6));
299
            
300
0
    case RTPC_SYSD:
301
0
        return (sizeof(struct sockaddr_un));
302
            
303
0
    default:
304
0
        break;
305
0
    }
306
307
0
    return (0);
308
0
}
309
310
void
311
rtpp_controlfd_cleanup(const struct rtpp_cfg *cfsp)
312
0
{
313
0
    struct rtpp_ctrl_sock *ctrl_sock;
314
315
0
    for (ctrl_sock = RTPP_LIST_HEAD(cfsp->ctrl_socks);
316
0
      ctrl_sock != NULL; ctrl_sock = RTPP_ITER_NEXT(ctrl_sock)) {
317
0
        if (RTPP_CTRL_ISUNIX(ctrl_sock) == 0)
318
0
            continue;
319
0
        unlink(ctrl_sock->cmd_sock);
320
0
    }
321
0
}
322
323
struct rtpp_ctrl_sock *
324
rtpp_ctrl_sock_parse(const char *optarg)
325
0
{
326
0
    struct rtpp_ctrl_sock *rcsp;
327
328
0
    rcsp = rtpp_zmalloc(sizeof(struct rtpp_ctrl_sock));
329
0
    if (rcsp == NULL) {
330
0
        return (NULL);
331
0
    }
332
0
    rcsp->type= RTPC_IFSUN;
333
0
    if (strncmp("udp:", optarg, 4) == 0) {
334
0
        rcsp->type= RTPC_UDP4;
335
0
        optarg += 4;
336
0
    } else if (strncmp("udp6:", optarg, 5) == 0) {
337
0
        rcsp->type= RTPC_UDP6;
338
0
        optarg += 5;
339
0
    } else if (strncmp("unix:", optarg, 5) == 0) {
340
0
        rcsp->type= RTPC_IFSUN;
341
0
        optarg += 5;
342
0
    } else if (strncmp("cunix:", optarg, 6) == 0) {
343
0
        rcsp->type= RTPC_IFSUN_C;
344
0
        optarg += 6;
345
0
    } else if (strncmp("systemd:", optarg, 8) == 0) {
346
0
        rcsp->type= RTPC_SYSD;
347
0
        optarg += 8;
348
0
    } else if (strncmp("stdio:", optarg, 6) == 0) {
349
0
        rcsp->type= RTPC_STDIO;
350
0
        optarg += 6;
351
0
    } else if (strncmp("stdioc:", optarg, 7) == 0) {
352
0
        rcsp->type= RTPC_STDIO;
353
0
        rcsp->exit_on_close = 1;
354
0
        optarg += 7;
355
0
#if defined(LIBRTPPROXY)
356
0
    } else if (strncmp("fd:", optarg, 3) == 0) {
357
0
        rcsp->type= RTPC_FD;
358
0
        optarg += 3;
359
0
#endif
360
0
    } else if (strncmp("tcp:", optarg, 4) == 0) {
361
0
        rcsp->type= RTPC_TCP4;
362
0
        optarg += 4;
363
0
    } else if (strncmp("tcp6:", optarg, 5) == 0) {
364
0
        rcsp->type= RTPC_TCP6;
365
0
        optarg += 5;
366
0
    }
367
0
    rcsp->cmd_sock = optarg;
368
369
0
    return (rcsp);
370
0
}
371
372
#if 0
373
const char *
374
rtpp_ctrl_sock_describe(struct rtpp_ctrl_sock *rcsp)
375
{
376
377
    switch (rcsp->type) {
378
    case RTPC_IFSUN:
379
        return "unix";
380
381
    case RTPC_UDP4:
382
        return "udp";
383
384
    case RTPC_UDP6:
385
        return "udp6";
386
387
    case RTPC_IFSUN_C:
388
        return "cunix";
389
390
    case RTPC_SYSD:
391
        return "systemd";
392
393
    case RTPC_STDIO:
394
        return "stdio";
395
396
    case RTPC_TCP4:
397
        return "tcp";
398
399
    case RTPC_TCP6:
400
        return "tcp6";
401
402
    default:
403
        abort();
404
    }
405
}
406
#endif