/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 | } |