Coverage Report

Created: 2026-09-03 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tcpreplay/src/common/services.c
Line
Count
Source
1
/* $Id$ */
2
3
/*
4
 *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
5
 *   Copyright (c) 2013-2026 Fred Klassen <tcpreplay.dev at gmail dot com> - AppNeta by Broadcom
6
 *
7
 *   The Tcpreplay Suite of tools is free software: you can redistribute it 
8
 *   and/or modify it under the terms of the GNU General Public License as 
9
 *   published by the Free Software Foundation, either version 3 of the 
10
 *   License, or with the authors permission any later version.
11
 *
12
 *   The Tcpreplay Suite is distributed in the hope that it will be useful,
13
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *   GNU General Public License for more details.
16
 *
17
 *   You should have received a copy of the GNU General Public License
18
 *   along with the Tcpreplay Suite.  If not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
#include "config.h"
22
#include "defines.h"
23
#include "common.h"
24
25
#include <regex.h>
26
#include <errno.h>
27
#include <string.h>
28
#include <stdlib.h>
29
30
/**
31
 * parses /etc/services so we know which ports are service ports
32
 */
33
void
34
parse_services(const char *file, tcpr_services_t *services)
35
81
{
36
81
    FILE *service = NULL;
37
81
    char service_line[MAXLINE], port[10], proto[10];
38
81
    regex_t preg;
39
81
    size_t nmatch = 3;
40
81
    regmatch_t pmatch[3];
41
81
    static const char regex[] = "([0-9]+)/(tcp|udp)"; /* matches the port as pmatch[1], service pmatch[2] */
42
43
81
    assert(file);
44
81
    assert(services);
45
46
81
    dbgx(1, "Parsing %s", file);
47
81
    memset(service_line, '\0', MAXLINE);
48
49
    /* mark all ports not a service */
50
81
    memset(&services->tcp[0], '\0', sizeof(services->tcp));
51
81
    memset(&services->udp[0], '\0', sizeof(services->udp));
52
53
81
    if ((service = fopen(file, "r")) == NULL) {
54
0
        errx(-1, "Unable to open service file: %s\n%s", file, strerror(errno));
55
0
    }
56
57
    /* compile our regexes */
58
81
    if ((regcomp(&preg, regex, REG_ICASE|REG_EXTENDED)) != 0) {
59
0
        errx(-1, "Unable to compile regex: %s", regex);
60
0
    }
61
62
    /* parse the entire file */
63
7.82k
    while ((fgets(service_line, MAXLINE, service)) != NULL) {
64
        /* zero out our vars */
65
7.74k
        memset(port, '\0', 10);
66
7.74k
        memset(proto, '\0', 10);
67
68
7.74k
        dbgx(4, "Processing: %s", service_line);
69
70
        /* look for format of 1234/tcp */
71
7.74k
        if ((regexec(&preg, service_line, nmatch, pmatch, 0)) == 0) { /* matches */
72
1.17k
            uint16_t portc;
73
1.17k
            size_t portlen = (size_t)(pmatch[1].rm_eo - pmatch[1].rm_so);
74
1.17k
            size_t protolen = (size_t)(pmatch[2].rm_eo - pmatch[2].rm_so);
75
76
            /*
77
             * strip out the port & proto from the line, clamping each copy to
78
             * its destination buffer. The "([0-9]+)" group has no upper bound,
79
             * so a line with an overlong digit run would otherwise overflow the
80
             * 10-byte port[] via strncpy() using the match length as the count.
81
             */
82
1.17k
            if (portlen >= sizeof(port)) {
83
267
                portlen = sizeof(port) - 1;
84
267
            }
85
1.17k
            if (protolen >= sizeof(proto)) {
86
0
                protolen = sizeof(proto) - 1;
87
0
            }
88
1.17k
            strncpy(port, &service_line[pmatch[1].rm_so], portlen);
89
1.17k
            port[portlen] = '\0';
90
1.17k
            strncpy(proto, &service_line[pmatch[2].rm_so], protolen);
91
1.17k
            proto[protolen] = '\0';
92
93
            /* convert port[] into an integer */
94
1.17k
            portc = (uint16_t)strtol(port, NULL, 10);
95
96
            /* update appropriate service array with the server port */
97
1.17k
            if (strcmp(proto, "tcp") == 0) {
98
351
                dbgx(3, "Setting TCP/%d as a server port", portc);
99
351
                services->tcp[portc] = 1; /* mark it as a service port */
100
821
            } else if (strcmp(proto, "udp") == 0) {
101
270
                dbgx(3, "Setting UDP/%d as a server port", portc);
102
270
                services->udp[portc] = 1;
103
551
            } else {
104
551
                warnx("Skipping unknown protocol service %s/%d", proto, portc);
105
551
            }
106
1.17k
        }
107
7.74k
    }
108
109
81
    regfree(&preg);
110
81
    fclose(service);
111
81
}