Coverage Report

Created: 2025-09-04 07:51

/src/fluent-bit/lib/monkey/mk_server/mk_config.c
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*  Monkey HTTP Server
4
 *  ==================
5
 *  Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
6
 *
7
 *  Licensed under the Apache License, Version 2.0 (the "License");
8
 *  you may not use this file except in compliance with the License.
9
 *  You may obtain a copy of the License at
10
 *
11
 *      http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 *  Unless required by applicable law or agreed to in writing, software
14
 *  distributed under the License is distributed on an "AS IS" BASIS,
15
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 *  See the License for the specific language governing permissions and
17
 *  limitations under the License.
18
 */
19
20
#include <monkey/monkey.h>
21
#include <monkey/mk_kernel.h>
22
#include <monkey/mk_config.h>
23
#include <monkey/mk_utils.h>
24
#include <monkey/mk_mimetype.h>
25
#include <monkey/mk_info.h>
26
#include <monkey/mk_core.h>
27
#include <monkey/mk_server.h>
28
#include <monkey/mk_plugin.h>
29
#include <monkey/mk_vhost.h>
30
#include <monkey/mk_mimetype.h>
31
#include <monkey/mk_info.h>
32
33
#include <ctype.h>
34
#include <limits.h>
35
#include <mk_core/mk_dirent.h>
36
#include <sys/stat.h>
37
38
struct mk_server_config *mk_config;
39
40
static int mk_config_key_have(struct mk_list *list, const char *value)
41
0
{
42
0
    struct mk_list *head;
43
0
    struct mk_string_line *entry;
44
45
0
    mk_list_foreach(head, list) {
46
0
        entry = mk_list_entry(head, struct mk_string_line, _head);
47
0
        if (strcasecmp(entry->val, value) == 0) {
48
0
            return MK_TRUE;
49
0
        }
50
0
    }
51
0
    return MK_FALSE;
52
0
}
53
54
void mk_config_listeners_free(struct mk_server *server)
55
0
{
56
0
    struct mk_list *tmp;
57
0
    struct mk_list *head;
58
0
    struct mk_config_listener *l;
59
60
0
    mk_list_foreach_safe(head, tmp, &server->listeners) {
61
0
        l = mk_list_entry(head, struct mk_config_listener, _head);
62
0
        mk_list_del(&l->_head);
63
0
        mk_mem_free(l->address);
64
0
        mk_mem_free(l->port);
65
0
        mk_mem_free(l);
66
0
    }
67
0
}
68
69
void mk_config_free_all(struct mk_server *server)
70
0
{
71
0
    mk_vhost_free_all(server);
72
0
    mk_mimetype_free_all(server);
73
74
0
    if (server->config) {
75
0
        mk_rconf_free(server->config);
76
0
    }
77
78
0
    if (server->path_conf_root) {
79
0
        mk_mem_free(server->path_conf_root);
80
0
    }
81
82
0
    if (server->path_conf_pidfile) {
83
0
        mk_mem_free(server->path_conf_pidfile);
84
0
    }
85
86
0
    if (server->conf_user_pub) {
87
0
        mk_mem_free(server->conf_user_pub);
88
0
    }
89
90
    /* free config->index_files */
91
0
    if (server->index_files) {
92
0
        mk_string_split_free(server->index_files);
93
0
    }
94
95
0
    if (server->user) {
96
0
        mk_mem_free(server->user);
97
0
    }
98
99
0
    if (server->transport_layer) {
100
0
        mk_mem_free(server->transport_layer);
101
0
    }
102
103
0
    mk_config_listeners_free(server);
104
105
0
    mk_ptr_free(&server->server_software);
106
0
    mk_mem_free(server);
107
0
}
108
109
/* Print a specific error */
110
static void mk_config_print_error_msg(char *variable, char *path)
111
0
{
112
0
    mk_err("[config] %s at %s has an invalid value",
113
0
           variable, path);
114
0
    mk_mem_free(path);
115
0
    exit(EXIT_FAILURE);
116
0
}
117
118
/*
119
 * Check if at least one of the Listen interfaces are being used by another
120
 * process.
121
 */
122
int mk_config_listen_check_busy(struct mk_server *server)
123
0
{
124
0
    int fd;
125
0
    struct mk_list *head;
126
0
    struct mk_plugin *p;
127
0
    struct mk_config_listener *listen;
128
129
0
    p = mk_plugin_cap(MK_CAP_SOCK_PLAIN, server);
130
0
    if (!p) {
131
0
        mk_warn("Listen check: consider build monkey with basic socket handling!");
132
0
        return MK_FALSE;
133
0
    }
134
135
0
    mk_list_foreach(head, &server->listeners) {
136
0
        listen = mk_list_entry(head, struct mk_config_listener, _head);
137
138
0
        fd = mk_socket_connect(listen->address, atol(listen->port), MK_FALSE);
139
0
        if (fd != -1) {
140
0
            close(fd);
141
0
            return MK_TRUE;
142
0
        }
143
0
    }
144
145
0
    return MK_FALSE;
146
0
}
147
148
int mk_config_listen_parse(char *value, struct mk_server *server)
149
0
{
150
0
    int ret = -1;
151
0
    int flags = 0;
152
0
    long port_num;
153
0
    char *address = NULL;
154
0
    char *port = NULL;
155
0
    char *divider;
156
0
    struct mk_list *list = NULL;
157
0
    struct mk_string_line *listener;
158
159
0
    list = mk_string_split_line(value);
160
0
    if (!list) {
161
0
        goto error;
162
0
    }
163
164
0
    if (mk_list_is_empty(list) == 0) {
165
0
        goto error;
166
0
    }
167
168
    /* Parse the listener interface */
169
0
    listener = mk_list_entry_first(list, struct mk_string_line, _head);
170
0
    if (listener->val[0] == '[') {
171
        /* IPv6 address */
172
0
        divider = strchr(listener->val, ']');
173
0
        if (divider == NULL) {
174
0
            mk_err("[config] Expected closing ']' in IPv6 address.");
175
0
            goto error;
176
0
        }
177
0
        if (divider[1] != ':' || divider[2] == '\0') {
178
0
            mk_err("[config] Expected ':port' after IPv6 address.");
179
0
            goto error;
180
0
        }
181
182
0
        address = mk_string_copy_substr(listener->val + 1, 0,
183
0
                                        divider - listener->val - 1);
184
0
        port = mk_string_dup(divider + 2);
185
0
    }
186
0
    else if (strchr(listener->val, ':') != NULL) {
187
        /* IPv4 address */
188
0
        divider = strrchr(listener->val, ':');
189
0
        if (divider == NULL || divider[1] == '\0') {
190
0
            mk_err("[config] Expected ':port' after IPv4 address.");
191
0
            goto error;
192
0
        }
193
194
0
        address = mk_string_copy_substr(listener->val, 0,
195
0
                                        divider - listener->val);
196
0
        port = mk_string_dup(divider + 1);
197
0
    }
198
0
    else {
199
        /* Port only */
200
0
        address = NULL;
201
0
        port = mk_string_dup(listener->val);
202
0
    }
203
204
0
    errno = 0;
205
0
    port_num = strtol(port, NULL, 10);
206
0
    if (errno != 0 || port_num == LONG_MAX || port_num == LONG_MIN) {
207
0
        mk_warn("Using defaults, could not understand \"Listen %s\"",
208
0
                listener->val);
209
0
        port = NULL;
210
0
    }
211
212
    /* Check extra properties of the listener */
213
0
    flags = MK_CAP_HTTP;
214
0
    if (mk_config_key_have(list, "!http")) {
215
0
        flags |= ~MK_CAP_HTTP;
216
0
    }
217
218
#ifdef MK_HAVE_HTTP2
219
    if (mk_config_key_have(list, "h2")) {
220
        flags |= (MK_CAP_HTTP2 | MK_CAP_SOCK_TLS);
221
    }
222
223
    if (mk_config_key_have(list, "h2c")) {
224
        flags |= MK_CAP_HTTP2;
225
    }
226
#endif
227
228
0
    if (mk_config_key_have(list, "tls")) {
229
0
        flags |= MK_CAP_SOCK_TLS;
230
0
    }
231
232
    /* register the new listener */
233
0
    mk_config_listener_add(address, port, flags, server);
234
0
    mk_string_split_free(list);
235
0
    list = NULL;
236
0
    ret = 0;
237
238
0
error:
239
0
    if (address) {
240
0
        mk_mem_free(address);
241
0
    }
242
0
    if (port) {
243
0
        mk_mem_free(port);
244
0
    }
245
0
    if (list) {
246
0
        mk_string_split_free(list);
247
0
    }
248
249
0
    return ret;
250
0
}
251
252
static int mk_config_listen_read(struct mk_rconf_section *section,
253
                                 struct mk_server *server)
254
0
{
255
0
    int ret;
256
0
    struct mk_list *cur;
257
0
    struct mk_rconf_entry *entry;
258
259
0
    mk_list_foreach(cur, &section->entries) {
260
0
        entry = mk_list_entry(cur, struct mk_rconf_entry, _head);
261
0
        if (strcasecmp(entry->key, "Listen")) {
262
0
            continue;
263
0
        }
264
265
0
        ret = mk_config_listen_parse(entry->val, server);
266
0
        if (ret != 0) {
267
0
            return -1;
268
0
        }
269
0
    }
270
271
0
    return 0;
272
0
}
273
274
/* Read configuration files */
275
static int mk_config_read_files(char *path_conf, char *file_conf,
276
                                struct mk_server *server)
277
0
{
278
0
    unsigned long len;
279
0
    char *tmp = NULL;
280
0
    struct stat checkdir;
281
0
    struct mk_rconf *cnf;
282
0
    struct mk_rconf_section *section;
283
284
0
    if (!path_conf) {
285
0
        return -1;
286
0
    }
287
288
0
    if (!file_conf) {
289
0
        file_conf = "monkey.conf";
290
0
    }
291
292
0
    server->path_conf_root = mk_string_dup(path_conf);
293
294
0
    if (stat(server->path_conf_root, &checkdir) == -1) {
295
0
        mk_err("ERROR: Cannot find/open '%s'", server->path_conf_root);
296
0
        return -1;
297
0
    }
298
299
0
    mk_string_build(&tmp, &len, "%s/%s", path_conf, file_conf);
300
0
    cnf = mk_rconf_open(tmp);
301
0
    if (!cnf) {
302
0
        mk_mem_free(tmp);
303
0
        mk_err("Cannot read '%s'", server->conf_main);
304
0
        return -1;
305
0
    }
306
0
    section = mk_rconf_section_get(cnf, "SERVER");
307
0
    if (!section) {
308
0
        mk_err("ERROR: No 'SERVER' section defined");
309
0
        return -1;
310
0
    }
311
312
    /* Map source configuration */
313
0
    server->config = cnf;
314
315
    /* Listen */
316
0
    if (!server->port_override) {
317
        /* Process each Listen entry */
318
0
        if (mk_config_listen_read(section, server)) {
319
0
            mk_err("[config] Failed to read listen sections.");
320
0
        }
321
0
        if (mk_list_is_empty(&server->listeners) == 0) {
322
0
            mk_warn("[config] No valid Listen entries found, set default");
323
0
            mk_config_listener_add(NULL, NULL, MK_CAP_HTTP, server);
324
0
        }
325
0
    }
326
0
    else {
327
0
        mk_config_listener_add(NULL, server->port_override,
328
0
                               MK_CAP_HTTP, server);
329
0
    }
330
331
    /* Number of thread workers */
332
0
    if (server->workers == -1) {
333
0
        server->workers = (size_t) mk_rconf_section_get_key(section,
334
0
                                                               "Workers",
335
0
                                                               MK_RCONF_NUM);
336
0
    }
337
338
0
    if (server->workers < 1) {
339
0
        server->workers = mk_utils_get_system_core_count();
340
341
0
        if (server->workers < 1) {
342
0
            mk_config_print_error_msg("Workers", tmp);
343
0
        }
344
0
    }
345
346
    /* Timeout */
347
0
    server->timeout = (size_t) mk_rconf_section_get_key(section,
348
0
                                                           "Timeout", MK_RCONF_NUM);
349
0
    if (server->timeout < 1) {
350
0
        mk_config_print_error_msg("Timeout", tmp);
351
0
    }
352
353
    /* KeepAlive */
354
0
    server->keep_alive = (size_t) mk_rconf_section_get_key(section,
355
0
                                                              "KeepAlive",
356
0
                                                              MK_RCONF_BOOL);
357
0
    if (server->keep_alive == MK_ERROR) {
358
0
        mk_config_print_error_msg("KeepAlive", tmp);
359
0
    }
360
361
    /* MaxKeepAliveRequest */
362
0
    server->max_keep_alive_request = (size_t)
363
0
        mk_rconf_section_get_key(section,
364
0
                                 "MaxKeepAliveRequest",
365
0
                                 MK_RCONF_NUM);
366
367
0
    if (server->max_keep_alive_request == 0) {
368
0
        mk_config_print_error_msg("MaxKeepAliveRequest", tmp);
369
0
    }
370
371
    /* KeepAliveTimeout */
372
0
    server->keep_alive_timeout = (size_t) mk_rconf_section_get_key(section,
373
0
                                                                      "KeepAliveTimeout",
374
0
                                                                      MK_RCONF_NUM);
375
0
    if (server->keep_alive_timeout == 0) {
376
0
        mk_config_print_error_msg("KeepAliveTimeout", tmp);
377
0
    }
378
379
    /* Pid File */
380
0
    if (!server->path_conf_pidfile) {
381
0
        server->path_conf_pidfile = mk_rconf_section_get_key(section,
382
0
                                                                "PidFile",
383
0
                                                                MK_RCONF_STR);
384
0
    }
385
386
    /* Home user's directory /~ */
387
0
    server->conf_user_pub = mk_rconf_section_get_key(section,
388
0
                                                        "UserDir",
389
0
                                                        MK_RCONF_STR);
390
391
    /* Index files */
392
0
    server->index_files = mk_rconf_section_get_key(section,
393
0
                                                      "Indexfile", MK_RCONF_LIST);
394
395
    /* HideVersion Variable */
396
0
    server->hideversion = (size_t) mk_rconf_section_get_key(section,
397
0
                                                         "HideVersion",
398
0
                                                         MK_RCONF_BOOL);
399
0
    if (server->hideversion == MK_ERROR) {
400
0
        mk_config_print_error_msg("HideVersion", tmp);
401
0
    }
402
403
    /* User Variable */
404
0
    server->user = mk_rconf_section_get_key(section, "User", MK_RCONF_STR);
405
406
    /* Resume */
407
0
    server->resume = (size_t) mk_rconf_section_get_key(section,
408
0
                                                          "Resume", MK_RCONF_BOOL);
409
0
    if (server->resume == MK_ERROR) {
410
0
        mk_config_print_error_msg("Resume", tmp);
411
0
    }
412
413
    /* Max Request Size */
414
0
    server->max_request_size = (size_t) mk_rconf_section_get_key(section,
415
0
                                                              "MaxRequestSize",
416
0
                                                              MK_RCONF_NUM);
417
0
    if (server->max_request_size <= 0) {
418
0
        mk_config_print_error_msg("MaxRequestSize", tmp);
419
0
    }
420
0
    else {
421
0
        server->max_request_size *= 1024;
422
0
    }
423
424
    /* Symbolic Links */
425
0
    server->symlink = (size_t) mk_rconf_section_get_key(section,
426
0
                                                     "SymLink", MK_RCONF_BOOL);
427
0
    if (server->symlink == MK_ERROR) {
428
0
        mk_config_print_error_msg("SymLink", tmp);
429
0
    }
430
431
    /* Transport Layer plugin */
432
0
    if (!server->transport_layer) {
433
0
        server->transport_layer = mk_rconf_section_get_key(section,
434
0
                                                              "TransportLayer",
435
0
                                                              MK_RCONF_STR);
436
0
    }
437
438
    /* Default Mimetype */
439
0
    mk_mem_free(tmp);
440
0
    tmp = mk_rconf_section_get_key(section, "DefaultMimeType", MK_RCONF_STR);
441
0
    if (tmp) {
442
0
        mk_string_build(&server->mimetype_default_str, &len, "%s\r\n", tmp);
443
0
    }
444
445
    /* File Descriptor Table (FDT) */
446
0
    server->fdt = (size_t) mk_rconf_section_get_key(section,
447
0
                                                    "FDT",
448
0
                                                    MK_RCONF_BOOL);
449
450
    /* FIXME: Overcapacity not ready */
451
0
    server->fd_limit = (size_t) mk_rconf_section_get_key(section,
452
0
                                                           "FDLimit",
453
0
                                                           MK_RCONF_NUM);
454
    /* Get each worker clients capacity based on FDs system limits */
455
0
    server->server_capacity = mk_server_capacity(server);
456
457
458
0
    if (!server->one_shot) {
459
0
        mk_vhost_init(path_conf, server);
460
0
    }
461
0
    else {
462
0
        mk_vhost_set_single(server->one_shot, server);
463
0
    }
464
465
0
    mk_mem_free(tmp);
466
0
    return 0;
467
0
}
468
469
void mk_config_signature(struct mk_server *server)
470
0
{
471
0
    unsigned long len;
472
473
    /* Server Signature */
474
0
    if (server->hideversion == MK_FALSE) {
475
0
        snprintf(server->server_signature,
476
0
                 sizeof(server->server_signature) - 1,
477
0
                 "Monkey/%s", MK_VERSION_STR);
478
0
    }
479
0
    else {
480
0
        snprintf(server->server_signature,
481
0
                 sizeof(server->server_signature) - 1,
482
0
                 "Monkey");
483
0
    }
484
0
    len = snprintf(server->server_signature_header,
485
0
                   sizeof(server->server_signature_header) - 1,
486
0
                   "Server: %s\r\n", server->server_signature);
487
0
    server->server_signature_header_len = len;
488
0
}
489
490
/* read main configuration from monkey.conf */
491
void mk_config_start_configure(struct mk_server *server)
492
0
{
493
0
    int ret;
494
0
    unsigned long len;
495
496
0
    ret = mk_config_read_files(server->path_conf_root,
497
0
                               server->conf_main, server);
498
0
    if (ret != 0) {
499
0
        return;
500
0
    }
501
502
    /* Load mimes */
503
0
    mk_mimetype_read_config(server);
504
505
0
    mk_ptr_reset(&server->server_software);
506
507
    /* Basic server information */
508
0
    if (server->hideversion == MK_FALSE) {
509
0
        mk_string_build(&server->server_software.data,
510
0
                        &len, "Monkey/%s (%s)", MK_VERSION_STR, MK_BUILD_OS);
511
0
        server->server_software.len = len;
512
0
    }
513
0
    else {
514
0
        mk_string_build(&server->server_software.data, &len, "Monkey Server");
515
0
        server->server_software.len = len;
516
0
    }
517
0
}
518
519
/* Register a new listener into the main configuration */
520
struct mk_config_listener *mk_config_listener_add(char *address,
521
                                                  char *port, int flags,
522
                                                  struct mk_server *server)
523
0
{
524
0
    struct mk_list *head;
525
0
    struct mk_config_listener *check;
526
0
    struct mk_config_listener *listen = NULL;
527
528
0
    listen = mk_mem_alloc(sizeof(struct mk_config_listener));
529
0
    if (!listen) {
530
0
        mk_err("[listen_add] malloc() failed");
531
0
        return NULL;
532
0
    }
533
534
0
    if (!address) {
535
0
        listen->address = mk_string_dup(MK_DEFAULT_LISTEN_ADDR);
536
0
    }
537
0
    else {
538
0
        listen->address = mk_string_dup(address);
539
0
    }
540
541
    /* Set the port */
542
0
    if (!port) {
543
0
        mk_err("[listen_add] TCP port not defined");
544
0
        exit(EXIT_FAILURE);
545
0
    }
546
547
0
    listen->port = mk_string_dup(port);
548
0
    listen->flags = flags;
549
550
    /* Before to add a new listener, lets make sure it's not a duplicated */
551
0
    mk_list_foreach(head, &server->listeners) {
552
0
        check = mk_list_entry(head, struct mk_config_listener, _head);
553
0
        if (strcmp(listen->address, check->address) == 0 &&
554
0
            strcmp(listen->port, check->port) == 0) {
555
0
            mk_warn("Listener: duplicated %s:%s, skip.",
556
0
                    listen->address, listen->port);
557
558
            /* free resources */
559
0
            mk_mem_free(listen->address);
560
0
            mk_mem_free(listen->port);
561
0
            mk_mem_free(listen);
562
0
            return NULL;
563
0
        }
564
0
    }
565
566
0
    mk_list_add(&listen->_head, &server->listeners);
567
0
    return listen;
568
0
}
569
570
void mk_config_set_init_values(struct mk_server *server)
571
0
{
572
    /* Init values */
573
0
    server->is_seteuid = MK_FALSE;
574
0
    server->timeout = 15;
575
0
    server->hideversion = MK_FALSE;
576
0
    server->keep_alive = MK_TRUE;
577
0
    server->keep_alive_timeout = 15;
578
0
    server->max_keep_alive_request = 50;
579
0
    server->resume = MK_TRUE;
580
0
    server->standard_port = 80;
581
0
    server->symlink = MK_FALSE;
582
0
    server->nhosts = 0;
583
0
    mk_list_init(&server->hosts);
584
0
    server->user = NULL;
585
0
    server->open_flags = O_RDONLY; /* The only place this is effectively used (other than the sanity check) 
586
                                    * is mk_http.c where it's used to test for file existence and the fd is apparently leaked */
587
0
    server->index_files = NULL;
588
0
    server->conf_user_pub = NULL;
589
0
    server->workers = 1;
590
591
    /* TCP REUSEPORT: available on Linux >= 3.9 */
592
0
    if (server->scheduler_mode == -1) {
593
0
        if (server->kernel_features & MK_KERNEL_SO_REUSEPORT) {
594
0
            server->scheduler_mode = MK_SCHEDULER_REUSEPORT;
595
0
        }
596
0
        else {
597
0
            server->scheduler_mode = MK_SCHEDULER_FAIR_BALANCING;
598
0
        }
599
0
    }
600
601
    /* Max request buffer size allowed
602
     * right now, every chunk size is 4KB (4096 bytes),
603
     * so we are setting a maximum request size to 32 KB */
604
0
    server->max_request_size = MK_REQUEST_CHUNK * 8;
605
606
    /* Internals */
607
0
    server->safe_event_write = MK_FALSE;
608
609
    /* Init plugin list */
610
0
    mk_list_init(&server->plugins);
611
612
    /* Init listeners */
613
0
    mk_list_init(&server->listeners);
614
0
}
615
616
void mk_config_sanity_check(struct mk_server *server)
617
0
{
618
    /* Check O_NOATIME for current user, flag will just be used
619
     * if running user is allowed to.
620
     */
621
0
    int fd;
622
0
    int flags;
623
624
0
    if (!server->path_conf_root) {
625
0
        return;
626
0
    }
627
628
0
    flags = server->open_flags;
629
0
    flags |= O_NOATIME;
630
0
    fd = open(server->path_conf_root, flags);
631
632
0
    if (fd > -1) {
633
0
        server->open_flags = flags;
634
0
        close(fd);
635
0
    }
636
0
}