Blame


1 3db5bc7c 2024-06-17 op /*
2 3db5bc7c 2024-06-17 op * Copyright (c) 2024 github.com/Sir-Photch <sir-photch@posteo.me>
3 3db5bc7c 2024-06-17 op *
4 3db5bc7c 2024-06-17 op * Permission to use, copy, modify, and distribute this software for any
5 3db5bc7c 2024-06-17 op * purpose with or without fee is hereby granted, provided that the above
6 3db5bc7c 2024-06-17 op * copyright notice and this permission notice appear in all copies.
7 3db5bc7c 2024-06-17 op *
8 3db5bc7c 2024-06-17 op * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 3db5bc7c 2024-06-17 op * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 3db5bc7c 2024-06-17 op * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 3db5bc7c 2024-06-17 op * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 3db5bc7c 2024-06-17 op * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 3db5bc7c 2024-06-17 op * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 3db5bc7c 2024-06-17 op * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 3db5bc7c 2024-06-17 op */
16 3db5bc7c 2024-06-17 op
17 3db5bc7c 2024-06-17 op #include "gmid.h"
18 3db5bc7c 2024-06-17 op
19 3db5bc7c 2024-06-17 op #include <stdint.h>
20 3db5bc7c 2024-06-17 op #include <string.h>
21 3db5bc7c 2024-06-17 op
22 3db5bc7c 2024-06-17 op #define MIN(a, b) (a) < (b) ? (a) : (b)
23 3db5bc7c 2024-06-17 op
24 cc399bfa 2024-06-17 op static int
25 3db5bc7c 2024-06-17 op check_prefix_v1(char **buf)
26 3db5bc7c 2024-06-17 op {
27 cc399bfa 2024-06-17 op static const char PROXY[6] = "PROXY ";
28 3db5bc7c 2024-06-17 op
29 f92ef76b 2024-06-17 op if (strncmp(*buf, PROXY, sizeof(PROXY)) != 0)
30 27c6dc18 2024-06-17 op return (-1);
31 3db5bc7c 2024-06-17 op
32 cc399bfa 2024-06-17 op *buf += sizeof(PROXY);
33 3db5bc7c 2024-06-17 op
34 27c6dc18 2024-06-17 op return (0);
35 3db5bc7c 2024-06-17 op }
36 3db5bc7c 2024-06-17 op
37 3db5bc7c 2024-06-17 op static int
38 3db5bc7c 2024-06-17 op check_proto_v1(char **buf)
39 3db5bc7c 2024-06-17 op {
40 cc399bfa 2024-06-17 op static const char TCP[3] = "TCP";
41 3db5bc7c 2024-06-17 op
42 f92ef76b 2024-06-17 op if (strncmp(*buf, TCP, sizeof(TCP)) != 0)
43 27c6dc18 2024-06-17 op return (-1);
44 3db5bc7c 2024-06-17 op
45 cc399bfa 2024-06-17 op *buf += sizeof(TCP);
46 3db5bc7c 2024-06-17 op
47 cc399bfa 2024-06-17 op int type;
48 cc399bfa 2024-06-17 op switch ((*buf)[0]) {
49 cc399bfa 2024-06-17 op case '4': type = 4; break;
50 cc399bfa 2024-06-17 op case '6': type = 6; break;
51 27c6dc18 2024-06-17 op default: return (-1);
52 cc399bfa 2024-06-17 op }
53 3db5bc7c 2024-06-17 op
54 2a090b86 2024-06-17 op if ((*buf)[1] != ' ')
55 2a090b86 2024-06-17 op return (-1);
56 2a090b86 2024-06-17 op
57 cc399bfa 2024-06-17 op // '4' / '6' + ' '
58 cc399bfa 2024-06-17 op *buf += 2;
59 3db5bc7c 2024-06-17 op
60 cc399bfa 2024-06-17 op return type;
61 3db5bc7c 2024-06-17 op }
62 3db5bc7c 2024-06-17 op
63 3db5bc7c 2024-06-17 op static int
64 3db5bc7c 2024-06-17 op check_unknown_v1(char **buf)
65 3db5bc7c 2024-06-17 op {
66 cc399bfa 2024-06-17 op static const char UNKNOWN[7] = "UNKNOWN";
67 3db5bc7c 2024-06-17 op
68 f92ef76b 2024-06-17 op if (strncmp(*buf, UNKNOWN, sizeof(UNKNOWN)) != 0)
69 27c6dc18 2024-06-17 op return (-1);
70 3db5bc7c 2024-06-17 op
71 cc399bfa 2024-06-17 op *buf += sizeof(UNKNOWN);
72 3db5bc7c 2024-06-17 op
73 27c6dc18 2024-06-17 op return (0);
74 3db5bc7c 2024-06-17 op }
75 3db5bc7c 2024-06-17 op
76 3db5bc7c 2024-06-17 op static int
77 3db5bc7c 2024-06-17 op check_crlf_v1(char *const *buf, size_t buflen)
78 3db5bc7c 2024-06-17 op {
79 cc399bfa 2024-06-17 op static const char CRLF[2] = "\r\n";
80 3db5bc7c 2024-06-17 op
81 cc399bfa 2024-06-17 op if (buflen < sizeof(CRLF))
82 27c6dc18 2024-06-17 op return (-1);
83 3db5bc7c 2024-06-17 op
84 cc399bfa 2024-06-17 op if (!memmem(*buf, buflen, CRLF, sizeof(CRLF)))
85 27c6dc18 2024-06-17 op return (-1);
86 3db5bc7c 2024-06-17 op
87 27c6dc18 2024-06-17 op return (0);
88 3db5bc7c 2024-06-17 op }
89 3db5bc7c 2024-06-17 op
90 3db5bc7c 2024-06-17 op static int
91 3db5bc7c 2024-06-17 op check_ip_v1(int af, void *addr, char **buf)
92 3db5bc7c 2024-06-17 op {
93 cc399bfa 2024-06-17 op char *spc;
94 3db5bc7c 2024-06-17 op
95 f92ef76b 2024-06-17 op if ((spc = strchr(*buf, ' ')) == NULL)
96 27c6dc18 2024-06-17 op return (-1);
97 3db5bc7c 2024-06-17 op
98 cc399bfa 2024-06-17 op *spc++ = '\0';
99 3db5bc7c 2024-06-17 op
100 f92ef76b 2024-06-17 op if (inet_pton(af, *buf, addr) != 1)
101 27c6dc18 2024-06-17 op return (-1);
102 3db5bc7c 2024-06-17 op
103 cc399bfa 2024-06-17 op *buf = spc;
104 3db5bc7c 2024-06-17 op
105 27c6dc18 2024-06-17 op return (0);
106 3db5bc7c 2024-06-17 op }
107 3db5bc7c 2024-06-17 op
108 3db5bc7c 2024-06-17 op static int
109 3db5bc7c 2024-06-17 op check_port_v1(uint16_t *port, char **buf, size_t *buflen)
110 3db5bc7c 2024-06-17 op {
111 cc399bfa 2024-06-17 op size_t wspc_idx = strcspn(*buf, " \r");
112 cc399bfa 2024-06-17 op char *wspc = *buf + wspc_idx;
113 3db5bc7c 2024-06-17 op
114 f92ef76b 2024-06-17 op if (!(*wspc == ' ' || *wspc == '\r'))
115 27c6dc18 2024-06-17 op return (-1);
116 3db5bc7c 2024-06-17 op
117 cc399bfa 2024-06-17 op *wspc++ = '\0';
118 3db5bc7c 2024-06-17 op
119 cc399bfa 2024-06-17 op const char *errstr;
120 cc399bfa 2024-06-17 op long long num = strtonum(*buf, 0, UINT16_MAX, &errstr);
121 cc399bfa 2024-06-17 op if (errstr)
122 27c6dc18 2024-06-17 op return (-1);
123 3db5bc7c 2024-06-17 op
124 cc399bfa 2024-06-17 op *buf = wspc;
125 cc399bfa 2024-06-17 op *port = num;
126 3db5bc7c 2024-06-17 op
127 27c6dc18 2024-06-17 op return (0);
128 3db5bc7c 2024-06-17 op }
129 3db5bc7c 2024-06-17 op
130 cc399bfa 2024-06-17 op int
131 cc399bfa 2024-06-17 op proxy_proto_v1_parse(struct proxy_protocol_v1 *s, char *buf, size_t buflen,
132 cc399bfa 2024-06-17 op size_t *consumed)
133 3db5bc7c 2024-06-17 op {
134 cc399bfa 2024-06-17 op const char *begin = buf;
135 3db5bc7c 2024-06-17 op
136 27c6dc18 2024-06-17 op if (check_crlf_v1(&buf, buflen) == -1 ||
137 27c6dc18 2024-06-17 op check_prefix_v1(&buf) == -1)
138 27c6dc18 2024-06-17 op return (-1);
139 3db5bc7c 2024-06-17 op
140 27c6dc18 2024-06-17 op switch (check_proto_v1(&buf)) {
141 cc399bfa 2024-06-17 op case 4: s->proto = PROTO_V4; break;
142 cc399bfa 2024-06-17 op case 6: s->proto = PROTO_V6; break;
143 27c6dc18 2024-06-17 op case -1:
144 27c6dc18 2024-06-17 op if (check_unknown_v1(&buf) == -1)
145 27c6dc18 2024-06-17 op return (-1);
146 cc399bfa 2024-06-17 op s->proto = PROTO_UNKNOWN;
147 27c6dc18 2024-06-17 op return (0);
148 cc399bfa 2024-06-17 op default:
149 27c6dc18 2024-06-17 op return (-1);
150 cc399bfa 2024-06-17 op }
151 3db5bc7c 2024-06-17 op
152 cc399bfa 2024-06-17 op switch (s->proto) {
153 cc399bfa 2024-06-17 op case PROTO_V4:
154 27c6dc18 2024-06-17 op if (check_ip_v1(AF_INET, &s->srcaddr.v4, &buf) == -1 ||
155 27c6dc18 2024-06-17 op check_ip_v1(AF_INET, &s->dstaddr.v4, &buf) == -1)
156 27c6dc18 2024-06-17 op return (-1);
157 cc399bfa 2024-06-17 op break;
158 3db5bc7c 2024-06-17 op
159 cc399bfa 2024-06-17 op case PROTO_V6:
160 27c6dc18 2024-06-17 op if (check_ip_v1(AF_INET6, &s->srcaddr.v6, &buf) == -1 ||
161 27c6dc18 2024-06-17 op check_ip_v1(AF_INET6, &s->dstaddr.v6, &buf) == -1)
162 27c6dc18 2024-06-17 op return (-1);
163 cc399bfa 2024-06-17 op break;
164 3db5bc7c 2024-06-17 op
165 fb8311e4 2024-06-17 op default:
166 fb8311e4 2024-06-17 op return (-1);
167 cc399bfa 2024-06-17 op }
168 3db5bc7c 2024-06-17 op
169 27c6dc18 2024-06-17 op if (check_port_v1(&s->srcport, &buf, &buflen) == -1 ||
170 27c6dc18 2024-06-17 op check_port_v1(&s->dstport, &buf, &buflen) == -1)
171 27c6dc18 2024-06-17 op return (-1);
172 3db5bc7c 2024-06-17 op
173 fb8311e4 2024-06-17 op if (*buf != '\n')
174 fb8311e4 2024-06-17 op return (-1);
175 cc399bfa 2024-06-17 op buf += 1;
176 cc399bfa 2024-06-17 op
177 cc399bfa 2024-06-17 op *consumed = buf - begin;
178 27c6dc18 2024-06-17 op return (0);
179 3db5bc7c 2024-06-17 op }
180 3db5bc7c 2024-06-17 op
181 cc399bfa 2024-06-17 op int
182 cc399bfa 2024-06-17 op proxy_proto_v1_string(const struct proxy_protocol_v1 *s, char *buf,
183 cc399bfa 2024-06-17 op size_t buflen)
184 3db5bc7c 2024-06-17 op {
185 cc399bfa 2024-06-17 op // "0000:0000:0000:0000:0000:0000:0000:0000\0"
186 cc399bfa 2024-06-17 op char srcaddrbuf[40], dstaddrbuf[40];
187 cc399bfa 2024-06-17 op int ret;
188 cc399bfa 2024-06-17 op switch (s->proto) {
189 cc399bfa 2024-06-17 op case PROTO_UNKNOWN:
190 cc399bfa 2024-06-17 op ret = snprintf(buf, buflen, "unknown");
191 cc399bfa 2024-06-17 op goto fin;
192 cc399bfa 2024-06-17 op case PROTO_V4:
193 cc399bfa 2024-06-17 op inet_ntop(AF_INET, &s->srcaddr.v4, srcaddrbuf,
194 cc399bfa 2024-06-17 op sizeof(srcaddrbuf));
195 cc399bfa 2024-06-17 op inet_ntop(AF_INET, &s->dstaddr.v4, dstaddrbuf,
196 cc399bfa 2024-06-17 op sizeof(dstaddrbuf));
197 cc399bfa 2024-06-17 op break;
198 cc399bfa 2024-06-17 op case PROTO_V6:
199 cc399bfa 2024-06-17 op inet_ntop(AF_INET6, &s->srcaddr.v6, srcaddrbuf,
200 cc399bfa 2024-06-17 op sizeof(srcaddrbuf));
201 cc399bfa 2024-06-17 op inet_ntop(AF_INET6, &s->dstaddr.v6, dstaddrbuf,
202 cc399bfa 2024-06-17 op sizeof(dstaddrbuf));
203 cc399bfa 2024-06-17 op break;
204 cc399bfa 2024-06-17 op }
205 3db5bc7c 2024-06-17 op
206 cc399bfa 2024-06-17 op ret = snprintf(
207 cc399bfa 2024-06-17 op buf,
208 cc399bfa 2024-06-17 op buflen,
209 cc399bfa 2024-06-17 op "from %s port %u via %s port %u",
210 cc399bfa 2024-06-17 op srcaddrbuf,
211 cc399bfa 2024-06-17 op s->srcport,
212 cc399bfa 2024-06-17 op dstaddrbuf,
213 cc399bfa 2024-06-17 op s->dstport);
214 3db5bc7c 2024-06-17 op
215 3db5bc7c 2024-06-17 op fin:
216 cc399bfa 2024-06-17 op return ret;
217 3db5bc7c 2024-06-17 op }