-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathparse.c
153 lines (139 loc) · 4.26 KB
/
parse.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/**
* ratched - TLS connection router that performs a man-in-the-middle attack
* Copyright (C) 2017-2017 Johannes Bauer
*
* This file is part of ratched.
*
* ratched is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; this program is ONLY licensed under
* version 3 of the License, later versions are explicitly excluded.
*
* ratched is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ratched; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Johannes Bauer <[email protected]>
**/
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "parse.h"
#include "stringlist.h"
#include "logging.h"
bool safe_strtol(const char **string, long int *result, bool trailing_data_allowed) {
char *end;
errno = 0;
long int value = strtol(*string, &end, 10);
bool did_conversion = (*string != end);
bool success = did_conversion && (errno == 0);
if (!trailing_data_allowed) {
success = success && (*end == 0);
}
if (success) {
*result = value;
*string = end;
}
return success;
}
static bool next_char_is(const char **string, char c) {
bool success = (**string == c);
if (success) {
*string = *string + 1;
}
return success;
}
static bool internal_parse_ipv4(const char **ipv4, uint32_t *ip_nbo, bool trailing_data_allowed) {
long int ip[4];
if (
safe_strtol(ipv4, &ip[0], true)
&& (next_char_is(ipv4, '.'))
&& safe_strtol(ipv4, &ip[1], true)
&& (next_char_is(ipv4, '.'))
&& safe_strtol(ipv4, &ip[2], true)
&& (next_char_is(ipv4, '.'))
&& safe_strtol(ipv4, &ip[3], trailing_data_allowed)
) {
if (!trailing_data_allowed && (**ipv4 != 0)) {
/* No trailing data allowed, but present. */
return false;
}
for (int i = 0; i < 4; i++) {
if ((ip[i] < 0) || (ip[i] > 255)) {
return false;
}
}
uint32_t ip_hbo = (ip[0] << 24) | (ip[1] << 16) | (ip[2] << 8) | (ip[3] << 0);
*ip_nbo = htonl(ip_hbo);
return true;
}
return false;
}
bool parse_ipv4(const char *ipv4, uint32_t *ip_nbo) {
return internal_parse_ipv4(&ipv4, ip_nbo, false);
}
bool parse_ipv4_port(const char *ipv4_port, uint32_t *ip_nbo, uint16_t *port_nbo) {
long int port;
if (
internal_parse_ipv4(&ipv4_port, ip_nbo, true)
&& (next_char_is(&ipv4_port, ':'))
&& safe_strtol(&ipv4_port, &port, false)) {
if ((port > 0) && (port <= 65535)) {
*port_nbo = htons(port);
return true;
}
}
return false;
}
bool parse_hostname_port(const char *hostname_port, uint32_t *ip_nbo, uint16_t *port_nbo) {
struct stringlist_t list;
parse_stringlist(&list, hostname_port, ":");
if (list.token_cnt != 2) {
logmsg(LLVL_ERROR, "Expected two arguments for hostname:port combination, but got %d: \"%s\"", list.token_cnt, hostname_port);
free_stringlist(&list);
return false;
}
/* First try to parse hostname as an IPv4 address */
if (!parse_ipv4(list.tokens[0], ip_nbo)) {
/* If this doesn't work, try DNS lookup */
struct addrinfo addrinfo = {
.ai_family = AF_INET,
.ai_flags = AI_PASSIVE,
};
struct addrinfo *result;
int returnvalue = getaddrinfo(list.tokens[0], NULL, &addrinfo, &result);
if (returnvalue) {
logmsg(LLVL_ERROR, "DNS lookup of %s failed: %s", list.tokens[0], gai_strerror(returnvalue));
free_stringlist(&list);
return false;
}
*ip_nbo = ((struct sockaddr_in*)result->ai_addr)->sin_addr.s_addr;
freeaddrinfo(result);
}
/* Then parse the port number */
long int port;
const char *port_str = list.tokens[1];
if (!safe_strtol(&port_str, &port, false)) {
logmsg(LLVL_ERROR, "Could not pase port number \"%s\" as a valid integer.", list.tokens[1]);
free_stringlist(&list);
return false;
}
if ((port <= 0) || (port >= 65535)) {
logmsg(LLVL_ERROR, "%ld is not a valid port number.", port);
free_stringlist(&list);
return false;
}
*port_nbo = htons(port);
free_stringlist(&list);
return true;
}