Coverage Report

Created: 2026-01-17 06:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/isc/proxy2.c
Line
Count
Source
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
#include <isc/proxy2.h>
15
16
enum isc_proxy2_states {
17
  ISC_PROXY2_STATE_WAITING_SIGNATURE,
18
  ISC_PROXY2_STATE_WAITING_HEADER,
19
  ISC_PROXY2_STATE_WAITING_PAYLOAD, /* Addresses and TLVs */
20
  ISC_PROXY2_STATE_END
21
};
22
23
static inline void
24
isc__proxy2_handler_init_direct(isc_proxy2_handler_t *restrict handler,
25
        const uint16_t max_size,
26
        const isc_region_t *restrict data,
27
0
        isc_proxy2_handler_cb_t cb, void *cbarg) {
28
0
  *handler = (isc_proxy2_handler_t){ .result = ISC_R_UNSET,
29
0
             .max_size = max_size };
30
0
  isc_proxy2_handler_setcb(handler, cb, cbarg);
31
32
0
  if (data == NULL) {
33
0
    isc_buffer_init(&handler->hdrbuf, handler->buf,
34
0
        sizeof(handler->buf));
35
0
  } else {
36
0
    isc_buffer_init(&handler->hdrbuf, data->base, data->length);
37
0
    isc_buffer_add(&handler->hdrbuf, data->length);
38
0
  }
39
0
}
40
41
void
42
isc_proxy2_handler_init(isc_proxy2_handler_t *restrict handler, isc_mem_t *mctx,
43
      const uint16_t max_size, isc_proxy2_handler_cb_t cb,
44
0
      void *cbarg) {
45
0
  REQUIRE(handler != NULL);
46
0
  REQUIRE(mctx != NULL);
47
0
  REQUIRE(max_size == 0 || max_size >= ISC_PROXY2_HEADER_SIZE);
48
0
  REQUIRE(cb != NULL);
49
50
0
  isc__proxy2_handler_init_direct(handler, max_size, NULL, cb, cbarg);
51
52
0
  isc_mem_attach(mctx, &handler->mctx);
53
0
  isc_buffer_setmctx(&handler->hdrbuf, handler->mctx);
54
0
}
55
56
void
57
0
isc_proxy2_handler_uninit(isc_proxy2_handler_t *restrict handler) {
58
0
  REQUIRE(handler != NULL);
59
60
  /*
61
   * Uninitialising the object from withing the callback does not
62
   * make any sense.
63
   */
64
0
  INSIST(handler->calling_cb == false);
65
0
  if (handler->mctx != NULL) {
66
0
    isc_buffer_clearmctx(&handler->hdrbuf);
67
0
    isc_mem_detach(&handler->mctx);
68
0
  }
69
0
  isc_buffer_invalidate(&handler->hdrbuf);
70
0
}
71
72
void
73
0
isc_proxy2_handler_clear(isc_proxy2_handler_t *restrict handler) {
74
0
  REQUIRE(handler != NULL);
75
76
0
  *handler = (isc_proxy2_handler_t){ .result = ISC_R_UNSET,
77
0
             .mctx = handler->mctx,
78
0
             .cb = handler->cb,
79
0
             .cbarg = handler->cbarg,
80
0
             .hdrbuf = handler->hdrbuf,
81
0
             .max_size = handler->max_size };
82
83
0
  isc_buffer_clear(&handler->hdrbuf);
84
0
  isc_buffer_trycompact(&handler->hdrbuf);
85
0
}
86
87
isc_proxy2_handler_t *
88
isc_proxy2_handler_new(isc_mem_t *mctx, const uint16_t max_size,
89
0
           isc_proxy2_handler_cb_t cb, void *cbarg) {
90
0
  isc_proxy2_handler_t *newhandler;
91
92
0
  REQUIRE(mctx != NULL);
93
0
  REQUIRE(cb != NULL);
94
95
0
  newhandler = isc_mem_get(mctx, sizeof(*newhandler));
96
0
  isc_proxy2_handler_init(newhandler, mctx, max_size, cb, cbarg);
97
98
0
  return newhandler;
99
0
}
100
101
void
102
0
isc_proxy2_handler_free(isc_proxy2_handler_t **restrict phandler) {
103
0
  isc_proxy2_handler_t *restrict handler = NULL;
104
0
  isc_mem_t *mctx = NULL;
105
0
  REQUIRE(phandler != NULL && *phandler != NULL);
106
107
0
  handler = *phandler;
108
109
0
  isc_mem_attach(handler->mctx, &mctx);
110
0
  isc_proxy2_handler_uninit(handler);
111
0
  isc_mem_putanddetach(&mctx, handler, sizeof(*handler));
112
113
0
  *phandler = NULL;
114
0
}
115
116
void
117
isc_proxy2_handler_setcb(isc_proxy2_handler_t *restrict handler,
118
0
       isc_proxy2_handler_cb_t cb, void *cbarg) {
119
0
  REQUIRE(handler != NULL);
120
0
  REQUIRE(cb != NULL);
121
0
  handler->cb = cb;
122
0
  handler->cbarg = cbarg;
123
0
}
124
125
static inline int
126
0
proxy2_socktype_to_socktype(const isc_proxy2_socktype_t proxy_socktype) {
127
0
  int socktype = 0;
128
129
0
  switch (proxy_socktype) {
130
0
  case ISC_PROXY2_SOCK_UNSPEC:
131
0
    socktype = 0;
132
0
    break;
133
0
  case ISC_PROXY2_SOCK_STREAM:
134
0
    socktype = SOCK_STREAM;
135
0
    break;
136
0
  case ISC_PROXY2_SOCK_DGRAM:
137
0
    socktype = SOCK_DGRAM;
138
0
    break;
139
0
  default:
140
0
    ISC_UNREACHABLE();
141
0
  };
142
143
0
  return socktype;
144
0
}
145
146
static inline void
147
isc__proxy2_handler_callcb(isc_proxy2_handler_t *restrict handler,
148
         const isc_result_t result,
149
         const isc_proxy2_command_t cmd,
150
         const isc_proxy2_socktype_t proxy_socktype,
151
         const isc_sockaddr_t *src_addr,
152
         const isc_sockaddr_t *dst_addr,
153
         const isc_region_t *restrict tlv_data,
154
0
         const isc_region_t *restrict extra_data) {
155
0
  int socktype = 0;
156
157
0
  handler->result = result;
158
0
  handler->calling_cb = true;
159
160
0
  if (result != ISC_R_SUCCESS) {
161
0
    handler->cb(result, cmd, -1, NULL, NULL, NULL, NULL,
162
0
          handler->cbarg);
163
0
  } else {
164
0
    socktype = proxy2_socktype_to_socktype(proxy_socktype);
165
0
    handler->cb(result, cmd, socktype,
166
0
          proxy_socktype == ISC_PROXY2_SOCK_UNSPEC ? NULL
167
0
                     : src_addr,
168
0
          proxy_socktype == ISC_PROXY2_SOCK_UNSPEC ? NULL
169
0
                     : dst_addr,
170
0
          tlv_data->length == 0 ? NULL : tlv_data,
171
0
          extra_data->length == 0 ? NULL : extra_data,
172
0
          handler->cbarg);
173
0
  }
174
175
0
  handler->calling_cb = false;
176
0
}
177
178
static inline void
179
isc__proxy2_handler_error(isc_proxy2_handler_t *restrict handler,
180
0
        const isc_result_t result) {
181
0
  INSIST(result != ISC_R_SUCCESS);
182
0
  isc__proxy2_handler_callcb(handler, result, ISC_PROXY2_CMD_ILLEGAL,
183
0
           ISC_PROXY2_SOCK_ILLEGAL, NULL, NULL, NULL,
184
0
           NULL);
185
0
  if (result != ISC_R_NOMORE) {
186
0
    handler->state = ISC_PROXY2_STATE_END;
187
0
  }
188
0
}
189
190
static inline bool
191
0
isc__proxy2_handler_handle_signature(isc_proxy2_handler_t *restrict handler) {
192
0
  isc_region_t remaining = { 0, 0 };
193
0
  size_t len;
194
195
0
  isc_buffer_remainingregion(&handler->hdrbuf, &remaining);
196
0
  len = ISC_MIN(remaining.length, ISC_PROXY2_HEADER_SIGNATURE_SIZE);
197
198
0
  if (memcmp(ISC_PROXY2_HEADER_SIGNATURE, remaining.base, len) != 0) {
199
0
    isc__proxy2_handler_error(handler, ISC_R_UNEXPECTED);
200
0
    return false;
201
0
  } else if (len == ISC_PROXY2_HEADER_SIGNATURE_SIZE) {
202
0
    isc_buffer_forward(&handler->hdrbuf,
203
0
           ISC_PROXY2_HEADER_SIGNATURE_SIZE);
204
0
    handler->expect_data = ISC_PROXY2_HEADER_SIZE -
205
0
               ISC_PROXY2_HEADER_SIGNATURE_SIZE;
206
0
    handler->state++;
207
0
  } else {
208
0
    INSIST(len < ISC_PROXY2_HEADER_SIGNATURE_SIZE);
209
0
    isc__proxy2_handler_error(handler, ISC_R_NOMORE);
210
0
    return false;
211
0
  }
212
0
  return true;
213
0
}
214
215
static inline bool
216
0
isc__proxy2_handler_handle_header(isc_proxy2_handler_t *restrict handler) {
217
  /*
218
   * The PROXYv2 header can be described as (signature 'sig' has been
219
   * processed and verified already as a separate step):
220
   *
221
   *  struct proxy_hdr_v2 {
222
   *     uint8_t sig[12];  // hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A
223
   *     uint8_t ver_cmd;  // protocol version and command
224
   *     uint8_t fam;      // protocol family and address
225
   *     uint16_t len;     // number of following bytes part of the header
226
   *  };
227
   */
228
0
  uint8_t ver_cmd = 0;
229
0
  uint8_t cmd = 0;
230
0
  uint8_t fam = 0;
231
0
  uint16_t len = 0;
232
0
  int addrfamily = 0;
233
0
  int socktype = 0;
234
0
  size_t min_addr_payload_size = 0;
235
236
0
  ver_cmd = isc_buffer_getuint8(&handler->hdrbuf);
237
238
  /* extract version and check it */
239
0
  if ((ver_cmd & 0xF0U) >> 4 != 2) {
240
    /* only support for version 2 is implemented */
241
0
    isc__proxy2_handler_error(handler, ISC_R_NOTIMPLEMENTED);
242
0
    return false;
243
0
  }
244
245
  /* extract command */
246
0
  cmd = ver_cmd & 0xFU;
247
248
0
  fam = isc_buffer_getuint8(&handler->hdrbuf);
249
0
  len = isc_buffer_getuint16(&handler->hdrbuf);
250
251
0
  if (handler->max_size > 0 &&
252
0
      (len + ISC_PROXY2_HEADER_SIZE) > handler->max_size)
253
0
  {
254
0
    goto error_range;
255
0
  }
256
257
0
  handler->expect_data = len;
258
259
  /* extract address family and socket type */
260
0
  addrfamily = (fam & 0xF0U) >> 4;
261
0
  socktype = fam & 0xFU;
262
263
  /* dispatch on the command value */
264
0
  switch (cmd) {
265
0
  case ISC_PROXY2_CMD_LOCAL:
266
    /* LOCAL implies "unspec" mode */
267
0
    handler->cmd = ISC_PROXY2_CMD_LOCAL;
268
0
    if (addrfamily != ISC_PROXY2_AF_UNSPEC ||
269
0
        socktype != ISC_PROXY2_SOCK_UNSPEC)
270
0
    {
271
0
      goto error_unexpected;
272
0
    }
273
0
    handler->proxy_addr_family = ISC_PROXY2_AF_UNSPEC;
274
0
    handler->proxy_socktype = ISC_PROXY2_SOCK_UNSPEC;
275
0
    break;
276
0
  case ISC_PROXY2_CMD_PROXY:
277
0
    handler->cmd = ISC_PROXY2_CMD_PROXY;
278
0
    switch (addrfamily) {
279
0
    case ISC_PROXY2_AF_UNSPEC:
280
0
      if (socktype != ISC_PROXY2_SOCK_UNSPEC) {
281
0
        goto error_unexpected;
282
0
      }
283
0
      handler->proxy_addr_family = ISC_PROXY2_AF_UNSPEC;
284
0
      handler->proxy_socktype = ISC_PROXY2_SOCK_UNSPEC;
285
0
      break;
286
0
    case ISC_PROXY2_AF_INET:
287
0
    case ISC_PROXY2_AF_INET6:
288
0
    case ISC_PROXY2_AF_UNIX:
289
0
      handler->proxy_addr_family =
290
0
        (isc_proxy2_addrfamily_t)addrfamily;
291
0
      switch (socktype) {
292
0
      case ISC_PROXY2_SOCK_DGRAM:
293
0
      case ISC_PROXY2_SOCK_STREAM:
294
0
        handler->proxy_socktype =
295
0
          (isc_proxy2_socktype_t)socktype;
296
0
        break;
297
0
      default:
298
0
        goto error_unexpected;
299
0
      }
300
0
      break;
301
0
    default:
302
0
      goto error_unexpected;
303
0
    }
304
0
    break;
305
0
  default:
306
0
    goto error_unexpected;
307
0
  };
308
309
  /* verify if enough data will be available in the payload */
310
0
  switch (handler->proxy_addr_family) {
311
0
  case ISC_PROXY2_AF_INET:
312
0
    min_addr_payload_size = ISC_PROXY2_MIN_AF_INET_SIZE -
313
0
          ISC_PROXY2_HEADER_SIZE;
314
0
    break;
315
0
  case ISC_PROXY2_AF_INET6:
316
0
    min_addr_payload_size = ISC_PROXY2_MIN_AF_INET6_SIZE -
317
0
          ISC_PROXY2_HEADER_SIZE;
318
0
    break;
319
0
  case ISC_PROXY2_AF_UNIX:
320
0
    min_addr_payload_size = ISC_PROXY2_MIN_AF_UNIX_SIZE -
321
0
          ISC_PROXY2_HEADER_SIZE;
322
0
    break;
323
0
  default:
324
0
    break;
325
0
  }
326
327
0
  if (min_addr_payload_size > 0) {
328
0
    if (len < min_addr_payload_size) {
329
0
      goto error_range;
330
0
    }
331
0
    handler->tlv_data_size = len - min_addr_payload_size;
332
0
  }
333
334
0
  if (handler->tlv_data_size > 0 &&
335
0
      handler->tlv_data_size < ISC_PROXY2_TLV_HEADER_SIZE)
336
0
  {
337
0
    goto error_range;
338
0
  }
339
340
0
  handler->header_size = ISC_PROXY2_HEADER_SIZE + len;
341
342
0
  handler->state++;
343
344
0
  return true;
345
346
0
error_unexpected:
347
0
  isc__proxy2_handler_error(handler, ISC_R_UNEXPECTED);
348
0
  return false;
349
0
error_range:
350
0
  isc__proxy2_handler_error(handler, ISC_R_RANGE);
351
0
  return false;
352
0
}
353
354
static inline isc_result_t
355
isc__proxy2_handler_get_addresses(isc_proxy2_handler_t *restrict handler,
356
          isc_buffer_t *restrict hdrbuf,
357
          isc_sockaddr_t *restrict src_addr,
358
0
          isc_sockaddr_t *restrict dst_addr) {
359
0
  size_t addr_size = 0;
360
0
  void *psrc_addr = NULL, *pdst_addr = NULL;
361
0
  uint16_t src_port = 0, dst_port = 0;
362
363
0
  switch (handler->proxy_addr_family) {
364
0
  case ISC_PROXY2_AF_UNSPEC:
365
    /* in this case we are instructed to skip over the data */
366
0
    INSIST(handler->tlv_data_size == 0);
367
0
    isc_buffer_forward(hdrbuf, handler->expect_data);
368
0
    break;
369
0
  case ISC_PROXY2_AF_INET:
370
0
    addr_size = sizeof(src_addr->type.sin.sin_addr.s_addr);
371
    /*
372
     * IPv4 source and destination endpoint addresses can be
373
     * described as follows:
374
     *
375
     * struct {        // for TCP/UDP over IPv4, len = 12
376
     *   uint32_t src_addr;
377
     *   uint32_t dst_addr;
378
     *   uint16_t src_port;
379
     *   uint16_t dst_port;
380
     * } ipv4_addr;
381
     */
382
0
    psrc_addr = isc_buffer_current(hdrbuf);
383
0
    isc_buffer_forward(hdrbuf, addr_size);
384
385
0
    pdst_addr = isc_buffer_current(hdrbuf);
386
0
    isc_buffer_forward(hdrbuf, addr_size);
387
388
0
    src_port = isc_buffer_getuint16(hdrbuf);
389
0
    dst_port = isc_buffer_getuint16(hdrbuf);
390
391
0
    if (src_addr != NULL) {
392
0
      isc_sockaddr_fromin(src_addr, psrc_addr, src_port);
393
0
    }
394
0
    if (dst_addr != NULL) {
395
0
      isc_sockaddr_fromin(dst_addr, pdst_addr, dst_port);
396
0
    }
397
0
    break;
398
0
  case ISC_PROXY2_AF_INET6:
399
0
    addr_size = sizeof(src_addr->type.sin6.sin6_addr);
400
    /*
401
     * IPv4 source and destination endpoint addresses can be
402
     * described as follows:
403
     *
404
     * struct {        // for TCP/UDP over IPv6, len = 36
405
     *    uint8_t  src_addr[16];
406
     *    uint8_t  dst_addr[16];
407
     *    uint16_t src_port;
408
     *    uint16_t dst_port;
409
     * } ipv6_addr;
410
     */
411
0
    psrc_addr = isc_buffer_current(hdrbuf);
412
0
    isc_buffer_forward(hdrbuf, addr_size);
413
414
0
    pdst_addr = isc_buffer_current(hdrbuf);
415
0
    isc_buffer_forward(hdrbuf, addr_size);
416
417
0
    src_port = isc_buffer_getuint16(hdrbuf);
418
0
    dst_port = isc_buffer_getuint16(hdrbuf);
419
420
0
    if (src_addr != NULL) {
421
0
      isc_sockaddr_fromin6(src_addr, psrc_addr, src_port);
422
0
    }
423
424
0
    if (dst_addr != NULL) {
425
0
      isc_sockaddr_fromin6(dst_addr, pdst_addr, dst_port);
426
0
    }
427
0
    break;
428
0
  case ISC_PROXY2_AF_UNIX: {
429
    /*
430
     * UNIX domain sockets source and destination endpoint
431
     * addresses can be described as follows:
432
     *
433
     * struct {        // for AF_UNIX sockets, len = 216
434
     *    uint8_t src_addr[108];
435
     *    uint8_t dst_addr[108];
436
     * } unix_addr;
437
     *
438
     * We currently have no use for this address type, but we can
439
     * validate the data.
440
     */
441
0
    unsigned char *ret = NULL;
442
443
0
    addr_size = ISC_PROXY2_AF_UNIX_MAX_PATH_LEN;
444
445
0
    ret = memchr(isc_buffer_current(hdrbuf), '\0', addr_size);
446
0
    if (ret == NULL) {
447
      /*
448
       * Someone has attempted to send us a path string
449
       * without a terminating '\0' byte - not a friend
450
       * knocking at the door.
451
       */
452
0
      return ISC_R_RANGE;
453
0
    }
454
0
    isc_buffer_forward(hdrbuf, addr_size);
455
456
0
    ret = memchr(isc_buffer_current(hdrbuf), '\0', addr_size);
457
0
    if (ret == NULL) {
458
0
      return ISC_R_RANGE;
459
0
    }
460
0
    isc_buffer_forward(hdrbuf, addr_size);
461
0
  } break;
462
0
  default:
463
0
    UNREACHABLE();
464
0
  }
465
466
0
  return ISC_R_SUCCESS;
467
0
}
468
469
static inline void
470
0
isc__proxy2_handler_handle_payload(isc_proxy2_handler_t *restrict handler) {
471
0
  isc_result_t result;
472
0
  isc_sockaddr_t src_addr = { 0 }, dst_addr = { 0 };
473
474
0
  result = isc__proxy2_handler_get_addresses(handler, &handler->hdrbuf,
475
0
               &src_addr, &dst_addr);
476
477
0
  if (result != ISC_R_SUCCESS) {
478
0
    isc__proxy2_handler_error(handler, result);
479
0
    return;
480
0
  }
481
482
0
  if (handler->tlv_data_size > 0) {
483
0
    isc_buffer_remainingregion(&handler->hdrbuf,
484
0
             &handler->tlv_data);
485
0
    handler->tlv_data.length = handler->tlv_data_size;
486
0
    isc_buffer_forward(&handler->hdrbuf, handler->tlv_data_size);
487
0
    result = isc_proxy2_tlv_data_verify(&handler->tlv_data);
488
0
    if (result != ISC_R_SUCCESS) {
489
0
      isc__proxy2_handler_error(handler, result);
490
0
      return;
491
0
    }
492
0
  }
493
494
0
  isc_buffer_remainingregion(&handler->hdrbuf, &handler->extra_data);
495
0
  handler->expect_data = 0;
496
497
0
  handler->state++;
498
499
  /*
500
   * Treat AF_UNIX as AF_UNSPEC as we have no use for it, although
501
   * at this point we have fully verified the header.
502
   */
503
0
  if (handler->proxy_addr_family == ISC_PROXY2_AF_UNIX) {
504
0
    handler->proxy_addr_family = ISC_PROXY2_AF_UNSPEC;
505
0
    handler->proxy_socktype = ISC_PROXY2_SOCK_UNSPEC;
506
0
    handler->tlv_data = (isc_region_t){ 0 };
507
0
  }
508
509
0
  isc__proxy2_handler_callcb(
510
0
    handler, ISC_R_SUCCESS, handler->cmd, handler->proxy_socktype,
511
0
    &src_addr, &dst_addr, &handler->tlv_data, &handler->extra_data);
512
513
0
  return;
514
0
}
515
516
static inline bool
517
0
isc__proxy2_handler_handle_data(isc_proxy2_handler_t *restrict handler) {
518
0
  if (isc_buffer_remaininglength(&handler->hdrbuf) < handler->expect_data)
519
0
  {
520
0
    isc__proxy2_handler_error(handler, ISC_R_NOMORE);
521
0
    return false;
522
0
  }
523
524
0
  switch (handler->state) {
525
0
  case ISC_PROXY2_STATE_WAITING_SIGNATURE:
526
    /*
527
     * We check for signature no matter how many bytes of it we
528
     * have received. The idea is to not wait for the whole
529
     * signature to verify it at once, but to detect, e.g. port
530
     * scanners as early as possible. Should we receive data byte
531
     * by byte, we would detect the problem when processing the
532
     * first unexpected byte.
533
     */
534
0
    return isc__proxy2_handler_handle_signature(handler);
535
0
  case ISC_PROXY2_STATE_WAITING_HEADER:
536
    /*
537
     * Handle the rest of the header (except signature which we
538
     * heave verified by now).
539
     */
540
0
    return isc__proxy2_handler_handle_header(handler);
541
0
  case ISC_PROXY2_STATE_WAITING_PAYLOAD:
542
    /*
543
     * Handle the PROXYv2 header payload - addresses and TLVs.
544
     */
545
0
    isc__proxy2_handler_handle_payload(handler);
546
0
    break;
547
0
  default:
548
0
    UNREACHABLE();
549
0
    break;
550
0
  };
551
552
0
  return false;
553
0
}
554
555
static inline isc_result_t
556
0
isc__proxy2_handler_process_data(isc_proxy2_handler_t *restrict handler) {
557
0
  while (isc__proxy2_handler_handle_data(handler)) {
558
0
    if (handler->state == ISC_PROXY2_STATE_END) {
559
0
      break;
560
0
    }
561
0
  }
562
563
0
  return handler->result;
564
0
}
565
566
isc_result_t
567
isc_proxy2_handler_push_data(isc_proxy2_handler_t *restrict handler,
568
           const void *restrict buf,
569
0
           const unsigned int buf_size) {
570
0
  isc_result_t result;
571
572
0
  REQUIRE(handler != NULL);
573
0
  REQUIRE(buf != NULL && buf_size != 0);
574
575
0
  INSIST(!handler->calling_cb);
576
577
0
  if (handler->state == ISC_PROXY2_STATE_END) {
578
0
    isc_proxy2_handler_clear(handler);
579
0
  }
580
581
0
  isc_buffer_putmem(&handler->hdrbuf, buf, buf_size);
582
583
0
  result = isc__proxy2_handler_process_data(handler);
584
585
0
  return result;
586
0
}
587
588
isc_result_t
589
isc_proxy2_handler_push(isc_proxy2_handler_t *restrict handler,
590
0
      const isc_region_t *restrict region) {
591
0
  isc_result_t result;
592
593
0
  REQUIRE(handler != NULL);
594
0
  REQUIRE(region != NULL);
595
596
0
  result = isc_proxy2_handler_push_data(handler, region->base,
597
0
                region->length);
598
599
0
  return result;
600
0
}
601
602
static inline bool
603
0
proxy2_payload_is_processed(const isc_proxy2_handler_t *restrict handler) {
604
0
  if (handler->state < ISC_PROXY2_STATE_END ||
605
0
      handler->result != ISC_R_SUCCESS)
606
0
  {
607
0
    return false;
608
0
  }
609
610
0
  return true;
611
0
}
612
613
size_t
614
isc_proxy2_handler_header(const isc_proxy2_handler_t *restrict handler,
615
0
        isc_region_t *restrict region) {
616
0
  REQUIRE(handler != NULL);
617
0
  REQUIRE(region == NULL ||
618
0
    (region->base == NULL && region->length == 0));
619
620
0
  if (!proxy2_payload_is_processed(handler)) {
621
0
    return 0;
622
0
  }
623
624
0
  if (region != NULL) {
625
0
    region->base = isc_buffer_base(&handler->hdrbuf);
626
0
    region->length = handler->header_size;
627
0
  }
628
629
0
  return handler->header_size;
630
0
}
631
632
size_t
633
isc_proxy2_handler_tlvs(const isc_proxy2_handler_t *restrict handler,
634
0
      isc_region_t *restrict region) {
635
0
  REQUIRE(handler != NULL);
636
0
  REQUIRE(region == NULL ||
637
0
    (region->base == NULL && region->length == 0));
638
639
0
  if (!proxy2_payload_is_processed(handler)) {
640
0
    return 0;
641
0
  }
642
643
0
  SET_IF_NOT_NULL(region, handler->tlv_data);
644
645
0
  return handler->tlv_data.length;
646
0
}
647
648
size_t
649
isc_proxy2_handler_extra(const isc_proxy2_handler_t *restrict handler,
650
0
       isc_region_t *restrict region) {
651
0
  REQUIRE(handler != NULL);
652
0
  REQUIRE(region == NULL ||
653
0
    (region->base == NULL && region->length == 0));
654
655
0
  if (!proxy2_payload_is_processed(handler)) {
656
0
    return 0;
657
0
  }
658
659
0
  SET_IF_NOT_NULL(region, handler->extra_data);
660
661
0
  return handler->extra_data.length;
662
0
}
663
664
isc_result_t
665
0
isc_proxy2_handler_result(const isc_proxy2_handler_t *restrict handler) {
666
0
  REQUIRE(handler != NULL);
667
668
0
  return handler->result;
669
0
}
670
671
isc_result_t
672
isc_proxy2_handler_addresses(const isc_proxy2_handler_t *restrict handler,
673
           int *restrict psocktype,
674
           isc_sockaddr_t *restrict psrc_addr,
675
0
           isc_sockaddr_t *restrict pdst_addr) {
676
0
  size_t ret;
677
0
  isc_region_t header_region = { 0 };
678
0
  isc_buffer_t buf = { 0 };
679
680
0
  REQUIRE(handler != NULL);
681
682
0
  if (!proxy2_payload_is_processed(handler)) {
683
0
    return ISC_R_UNEXPECTED;
684
0
  }
685
686
0
  ret = isc_proxy2_handler_header(handler, &header_region);
687
0
  RUNTIME_CHECK(ret > 0);
688
689
0
  isc_buffer_init(&buf, header_region.base, header_region.length);
690
0
  isc_buffer_add(&buf, header_region.length);
691
0
  isc_buffer_forward(&buf, ISC_PROXY2_HEADER_SIZE);
692
693
0
  INSIST(handler->expect_data == 0);
694
695
0
  RETERR(isc__proxy2_handler_get_addresses(
696
0
    (isc_proxy2_handler_t *)handler, &buf, psrc_addr, pdst_addr));
697
698
0
  SET_IF_NOT_NULL(psocktype,
699
0
      proxy2_socktype_to_socktype(handler->proxy_socktype));
700
701
0
  return ISC_R_SUCCESS;
702
0
}
703
704
isc_result_t
705
isc_proxy2_tlv_iterate(const isc_region_t *restrict tlv_data,
706
0
           const isc_proxy2_tlv_cb_t cb, void *cbarg) {
707
0
  isc_result_t result = ISC_R_SUCCESS;
708
0
  isc_buffer_t tlvs = { 0 };
709
0
  size_t remaining;
710
711
  /*
712
   * TLV header can be described as follows:
713
   *
714
   *   struct {
715
   *       uint8_t type;
716
   *       uint8_t length_hi;
717
   *       uint8_t length_lo;
718
   *   };
719
   *
720
   */
721
722
0
  REQUIRE(tlv_data != NULL);
723
0
  REQUIRE(cb != NULL);
724
725
0
  isc_buffer_init(&tlvs, tlv_data->base, tlv_data->length);
726
0
  isc_buffer_add(&tlvs, tlv_data->length);
727
728
0
  while ((remaining = isc_buffer_remaininglength(&tlvs)) > 0) {
729
0
    uint8_t type = 0;
730
0
    uint16_t len = 0;
731
0
    isc_region_t current_tlv_data = { 0 };
732
0
    bool ret = false;
733
734
    /* not enough data for a TLV header */
735
0
    if (remaining < ISC_PROXY2_TLV_HEADER_SIZE) {
736
0
      result = ISC_R_RANGE;
737
0
      break;
738
0
    }
739
740
0
    type = isc_buffer_getuint8(&tlvs);
741
0
    len = isc_buffer_getuint16(&tlvs);
742
743
0
    if ((remaining - ISC_PROXY2_TLV_HEADER_SIZE) < len) {
744
0
      result = ISC_R_RANGE;
745
0
      break;
746
0
    }
747
748
0
    current_tlv_data.base = isc_buffer_current(&tlvs);
749
0
    current_tlv_data.length = len;
750
0
    isc_buffer_forward(&tlvs, len);
751
752
0
    ret = cb((isc_proxy2_tlv_type_t)type, &current_tlv_data, cbarg);
753
0
    if (!ret) {
754
0
      break;
755
0
    }
756
0
  }
757
758
0
  return result;
759
0
}
760
761
typedef struct proxy2_tls_cbarg {
762
  uint8_t client;
763
  bool client_cert_verified;
764
  isc_proxy2_tls_subtlv_cb_t cb;
765
  void *cbarg;
766
} tls_cbarg_t;
767
768
static bool
769
proxy2_tls_iter_cb(const isc_proxy2_tlv_type_t tlv_type,
770
0
       const isc_region_t *restrict data, void *cbarg) {
771
0
  bool ret = false;
772
0
  tls_cbarg_t *tls_cbarg = (tls_cbarg_t *)cbarg;
773
774
0
  ret = tls_cbarg->cb(tls_cbarg->client, tls_cbarg->client_cert_verified,
775
0
          (isc_proxy2_tlv_subtype_tls_t)tlv_type, data,
776
0
          tls_cbarg->cbarg);
777
778
0
  return ret;
779
0
}
780
781
isc_result_t
782
isc_proxy2_subtlv_tls_header_data(const isc_region_t *restrict tls_tlv_data,
783
          uint8_t *restrict pclient_flags,
784
0
          bool *restrict pclient_cert_verified) {
785
  /*
786
   * SSL/TLS TLV header can be described as follows:
787
   *
788
   *   struct {
789
   *       uint8_t  client_flags;
790
   *       uint32_t client_cert_not_verified;
791
   *   }
792
   */
793
0
  uint8_t *p = NULL;
794
0
  uint8_t client_flags = 0;
795
0
  bool client_cert_verified = false;
796
0
  uint32_t client_cert_verified_data = 0;
797
798
0
  REQUIRE(tls_tlv_data != NULL);
799
0
  REQUIRE(pclient_flags == NULL || *pclient_flags == 0);
800
0
  REQUIRE(pclient_cert_verified == NULL ||
801
0
    *pclient_cert_verified == false);
802
803
0
  if (tls_tlv_data->length < ISC_PROXY2_TLS_SUBHEADER_MIN_SIZE) {
804
0
    return ISC_R_RANGE;
805
0
  }
806
807
0
  p = tls_tlv_data->base;
808
809
0
  client_flags = *p;
810
0
  p++;
811
  /* We need this to avoid ASAN complain about unaligned access */
812
0
  memmove(&client_cert_verified_data, p, sizeof(uint32_t));
813
0
  client_cert_verified = ntohl(client_cert_verified_data) == 0;
814
815
0
  SET_IF_NOT_NULL(pclient_flags, client_flags);
816
0
  SET_IF_NOT_NULL(pclient_cert_verified, client_cert_verified);
817
818
0
  return ISC_R_SUCCESS;
819
0
}
820
821
isc_result_t
822
isc_proxy2_subtlv_tls_iterate(const isc_region_t *restrict tls_tlv_data,
823
            const isc_proxy2_tls_subtlv_cb_t cb,
824
0
            void *cbarg) {
825
0
  tls_cbarg_t tls_cbarg;
826
0
  isc_result_t result = ISC_R_SUCCESS;
827
0
  uint8_t *p = NULL;
828
0
  uint8_t client_flags = 0;
829
0
  bool client_cert_verified = false;
830
831
0
  REQUIRE(tls_tlv_data != NULL);
832
0
  REQUIRE(cb != NULL);
833
834
0
  if (tls_tlv_data->length < ISC_PROXY2_TLS_SUBHEADER_MIN_SIZE) {
835
0
    return ISC_R_RANGE;
836
0
  }
837
838
0
  RETERR(isc_proxy2_subtlv_tls_header_data(tls_tlv_data, &client_flags,
839
0
             &client_cert_verified));
840
841
0
  p = tls_tlv_data->base;
842
0
  p += ISC_PROXY2_TLS_SUBHEADER_MIN_SIZE;
843
844
0
  if (cb != NULL) {
845
0
    isc_region_t data = {
846
0
      .base = p,
847
0
      .length = tls_tlv_data->length -
848
0
          ISC_PROXY2_TLS_SUBHEADER_MIN_SIZE
849
0
    };
850
0
    tls_cbarg = (tls_cbarg_t){ .client = client_flags,
851
0
             .client_cert_verified =
852
0
               client_cert_verified,
853
0
             .cb = cb,
854
0
             .cbarg = cbarg };
855
0
    result = isc_proxy2_tlv_iterate(&data, proxy2_tls_iter_cb,
856
0
            &tls_cbarg);
857
0
  }
858
859
0
  return result;
860
0
}
861
862
typedef struct tls_subtlv_verify_cbarg {
863
  uint16_t *count;
864
  isc_result_t verif_result;
865
} tls_subtlv_verify_cbarg_t;
866
867
static bool
868
proxy2_subtlv_verify_iter_cb(const uint8_t client,
869
           const bool client_cert_verified,
870
           const isc_proxy2_tlv_subtype_tls_t tls_subtlv_type,
871
0
           const isc_region_t *restrict data, void *cbarg) {
872
0
  bool verify_count = false;
873
0
  tls_subtlv_verify_cbarg_t *restrict arg =
874
0
    (tls_subtlv_verify_cbarg_t *)cbarg;
875
0
  uint8_t type = tls_subtlv_type;
876
877
0
  UNUSED(client);
878
0
  UNUSED(client_cert_verified);
879
880
0
  if (type <= ISC_PROXY2_TLV_TYPE_TLS ||
881
0
      type == ISC_PROXY2_TLV_TYPE_NETNS)
882
0
  {
883
0
    arg->verif_result = ISC_R_UNEXPECTED;
884
0
    return false;
885
0
  }
886
887
0
  switch (tls_subtlv_type) {
888
0
  case ISC_PROXY2_TLV_SUBTYPE_TLS_VERSION:
889
0
  case ISC_PROXY2_TLV_SUBTYPE_TLS_CN:
890
0
  case ISC_PROXY2_TLV_SUBTYPE_TLS_SIG_ALG:
891
0
  case ISC_PROXY2_TLV_SUBTYPE_TLS_KEY_ALG:
892
0
    if (data->length == 0) {
893
0
      arg->verif_result = ISC_R_RANGE;
894
0
      return false;
895
0
    }
896
0
    arg->count[tls_subtlv_type]++;
897
0
    verify_count = true;
898
0
    break;
899
0
  default:
900
0
    break;
901
0
  };
902
903
0
  if (verify_count && arg->count[tls_subtlv_type] > 1) {
904
0
    arg->verif_result = ISC_R_UNEXPECTED;
905
0
    return false;
906
0
  }
907
908
0
  return true;
909
0
}
910
911
typedef struct tlv_verify_cbarg {
912
  uint16_t count[256];
913
  isc_result_t verify_result;
914
} tlv_verify_cbarg_t;
915
916
static bool
917
isc_proxy2_tlv_verify_cb(const isc_proxy2_tlv_type_t tlv_type,
918
0
       const isc_region_t *restrict data, void *cbarg) {
919
0
  bool verify_count = false;
920
0
  uint8_t client = 0;
921
0
  tlv_verify_cbarg_t *arg = (tlv_verify_cbarg_t *)cbarg;
922
923
0
  if (tlv_type == 0) {
924
    /* the TLV values start from 1 */
925
0
    goto error_unexpected;
926
0
  }
927
928
0
  switch (tlv_type) {
929
0
  case ISC_PROXY2_TLV_TYPE_ALPN:
930
0
  case ISC_PROXY2_TLV_TYPE_AUTHORITY:
931
0
  case ISC_PROXY2_TLV_TYPE_NETNS:
932
    /* these values need to be more than 0 bytes long */
933
0
    if (data->length == 0) {
934
0
      goto error_range;
935
0
    }
936
0
    arg->count[tlv_type]++;
937
0
    verify_count = true;
938
0
    break;
939
0
  case ISC_PROXY2_TLV_TYPE_CRC32C:
940
0
    if (data->length != sizeof(uint32_t)) {
941
0
      goto error_range;
942
0
    }
943
0
    arg->count[tlv_type]++;
944
0
    verify_count = true;
945
0
    break;
946
0
  case ISC_PROXY2_TLV_TYPE_UNIQUE_ID:
947
0
    if (data->length > 128) {
948
0
      goto error_range;
949
0
    }
950
0
    arg->count[tlv_type]++;
951
0
    verify_count = true;
952
0
    break;
953
0
  case ISC_PROXY2_TLV_TYPE_TLS: {
954
0
    tls_subtlv_verify_cbarg_t tls_cbarg = {
955
0
      .verif_result = ISC_R_SUCCESS, .count = arg->count
956
0
    };
957
0
    size_t tls_version_count, tls_cn_count;
958
959
0
    arg->verify_result =
960
0
      isc_proxy2_subtlv_tls_header_data(data, &client, NULL);
961
962
0
    if (arg->verify_result != ISC_R_SUCCESS) {
963
0
      return false;
964
0
    }
965
966
0
    arg->verify_result = isc_proxy2_subtlv_tls_iterate(
967
0
      data, proxy2_subtlv_verify_iter_cb, &tls_cbarg);
968
969
0
    if (arg->verify_result != ISC_R_SUCCESS) {
970
0
      return false;
971
0
    } else if (tls_cbarg.verif_result != ISC_R_SUCCESS) {
972
0
      arg->verify_result = tls_cbarg.verif_result;
973
0
      return false;
974
0
    }
975
976
    /*
977
     * if CLIENT_TLS flag is set - TLS version TLV must be present
978
     */
979
0
    tls_version_count =
980
0
      arg->count[ISC_PROXY2_TLV_SUBTYPE_TLS_VERSION];
981
982
0
    if ((client & ISC_PROXY2_CLIENT_TLS) != 0) {
983
0
      if (tls_version_count != 1) {
984
0
        goto error_unexpected;
985
0
      }
986
0
    } else if (tls_version_count > 0) {
987
      /* unexpected TLS version TLV */
988
0
      goto error_unexpected;
989
0
    }
990
991
    /*
992
     * If client cert was submitted, CLIENT_CERT_CONN or
993
     * CLIENT_CERT_SESS flags must be present alongside the
994
     * CLIENT_TLS flag.
995
     */
996
0
    tls_cn_count = arg->count[ISC_PROXY2_TLV_SUBTYPE_TLS_CN];
997
998
0
    if ((client & (ISC_PROXY2_CLIENT_CERT_CONN |
999
0
             ISC_PROXY2_CLIENT_CERT_SESS)) != 0)
1000
0
    {
1001
0
      if (tls_cn_count != 1 ||
1002
0
          (client & ISC_PROXY2_CLIENT_TLS) == 0)
1003
0
      {
1004
0
        goto error_unexpected;
1005
0
      }
1006
0
    } else if (tls_cn_count > 0) {
1007
      /* unexpected Common Name TLV */
1008
0
      goto error_unexpected;
1009
0
    }
1010
1011
0
    arg->count[tlv_type]++;
1012
0
    verify_count = true;
1013
0
  } break;
1014
0
  default:
1015
0
    break;
1016
0
  };
1017
1018
0
  if (verify_count && arg->count[tlv_type] > 1) {
1019
0
    goto error_unexpected;
1020
0
  }
1021
1022
0
  return true;
1023
1024
0
error_unexpected:
1025
0
  arg->verify_result = ISC_R_UNEXPECTED;
1026
0
  return false;
1027
1028
0
error_range:
1029
0
  arg->verify_result = ISC_R_RANGE;
1030
0
  return false;
1031
0
}
1032
1033
isc_result_t
1034
0
isc_proxy2_tlv_data_verify(const isc_region_t *restrict tlv_data) {
1035
0
  tlv_verify_cbarg_t cbarg = { .verify_result = ISC_R_SUCCESS };
1036
1037
0
  RETERR(isc_proxy2_tlv_iterate(tlv_data, isc_proxy2_tlv_verify_cb,
1038
0
              &cbarg));
1039
1040
0
  return cbarg.verify_result;
1041
0
}
1042
1043
isc_result_t
1044
isc_proxy2_header_handle_directly(const isc_region_t *restrict header_data,
1045
          const isc_proxy2_handler_cb_t cb,
1046
0
          void *cbarg) {
1047
0
  isc_result_t result;
1048
0
  isc_proxy2_handler_t handler = { 0 };
1049
1050
0
  REQUIRE(header_data != NULL);
1051
0
  REQUIRE(cb != NULL);
1052
1053
0
  isc__proxy2_handler_init_direct(&handler, 0, header_data, cb, cbarg);
1054
1055
0
  result = isc__proxy2_handler_process_data(&handler);
1056
1057
0
  return result;
1058
0
}
1059
1060
isc_result_t
1061
isc_proxy2_make_header(isc_buffer_t *restrict outbuf,
1062
           const isc_proxy2_command_t cmd, const int socktype,
1063
           const isc_sockaddr_t *restrict src_addr,
1064
           const isc_sockaddr_t *restrict dst_addr,
1065
0
           const isc_region_t *restrict tlv_data) {
1066
0
  size_t total_size = ISC_PROXY2_HEADER_SIZE;
1067
0
  uint8_t family = ISC_PROXY2_AF_UNSPEC;
1068
0
  isc_proxy2_socktype_t proxy_socktype = ISC_PROXY2_SOCK_UNSPEC;
1069
1070
0
  uint8_t ver_cmd = 0;
1071
0
  uint8_t fam_socktype = 0;
1072
0
  uint16_t len = 0;
1073
1074
0
  size_t addr_size = 0;
1075
0
  void *psrc_addr = NULL, *pdst_addr = NULL;
1076
  /*
1077
   * The complete PROXYv2 header can be described as follows:
1078
   *
1079
   * 1. Header:
1080
   *
1081
   * struct proxy_hdr_v2 {
1082
   *   uint8_t sig[12];      // hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A
1083
   *   uint8_t ver_cmd;      // protocol version and command
1084
   *   uint8_t fam_socktype; // protocol family and socket type
1085
   *   uint16_t len;         // number of following bytes
1086
   * };
1087
   *
1088
   * 2. Addresses:
1089
   *
1090
   * union proxy_addr {
1091
   *   struct {        // for TCP/UDP over IPv4, len = 12
1092
   *       uint32_t src_addr;
1093
   *       uint32_t dst_addr;
1094
   *       uint16_t src_port;
1095
   *       uint16_t dst_port;
1096
   *   } ipv4_addr;
1097
   *   struct {        // for TCP/UDP over IPv6, len = 36
1098
   *        uint8_t  src_addr[16];
1099
   *        uint8_t  dst_addr[16];
1100
   *        uint16_t src_port;
1101
   *        uint16_t dst_port;
1102
   *   } ipv6_addr;
1103
   *   struct {        // for AF_UNIX sockets, len = 216
1104
   *        uint8_t src_addr[108];
1105
   *        uint8_t dst_addr[108];
1106
   *   } unix_addr;
1107
   * };
1108
   *
1109
   * 3. TLVs (optional)
1110
   */
1111
1112
0
  REQUIRE(outbuf != NULL);
1113
0
  REQUIRE(cmd == ISC_PROXY2_CMD_PROXY || socktype == 0);
1114
0
  REQUIRE((src_addr == NULL && dst_addr == NULL) ||
1115
0
    (src_addr != NULL && dst_addr != NULL));
1116
0
  REQUIRE(src_addr == NULL ||
1117
0
    (isc_sockaddr_pf(src_addr) == isc_sockaddr_pf(dst_addr)));
1118
1119
0
  switch (cmd) {
1120
0
  case ISC_PROXY2_CMD_LOCAL:
1121
0
    family = ISC_PROXY2_AF_UNSPEC;
1122
0
    break;
1123
0
  case ISC_PROXY2_CMD_PROXY:
1124
0
    if (socktype == 0) {
1125
0
      family = ISC_PROXY2_AF_UNSPEC;
1126
0
    } else {
1127
0
      switch (isc_sockaddr_pf(src_addr)) {
1128
0
      case AF_INET:
1129
0
        family = ISC_PROXY2_AF_INET;
1130
0
        addr_size = sizeof(src_addr->type.sin.sin_addr);
1131
0
        total_size += addr_size * 2 +
1132
0
                sizeof(uint16_t) * 2;
1133
0
        psrc_addr = (void *)&src_addr->type.sin.sin_addr
1134
0
                .s_addr;
1135
0
        pdst_addr = (void *)&dst_addr->type.sin.sin_addr
1136
0
                .s_addr;
1137
0
        break;
1138
0
      case AF_INET6:
1139
0
        family = ISC_PROXY2_AF_INET6;
1140
0
        addr_size =
1141
0
          sizeof(src_addr->type.sin6.sin6_addr);
1142
0
        total_size += addr_size * 2 +
1143
0
                sizeof(uint16_t) * 2;
1144
0
        psrc_addr =
1145
0
          (void *)&src_addr->type.sin6.sin6_addr;
1146
0
        pdst_addr =
1147
0
          (void *)&dst_addr->type.sin6.sin6_addr;
1148
0
        break;
1149
0
      default:
1150
0
        return ISC_R_UNEXPECTED;
1151
0
      }
1152
0
    }
1153
0
    break;
1154
0
  default:
1155
0
    return ISC_R_UNEXPECTED;
1156
0
  }
1157
1158
0
  switch (socktype) {
1159
0
  case 0:
1160
0
    proxy_socktype = ISC_PROXY2_SOCK_UNSPEC;
1161
0
    break;
1162
0
  case SOCK_STREAM:
1163
0
    proxy_socktype = ISC_PROXY2_SOCK_STREAM;
1164
0
    break;
1165
0
  case SOCK_DGRAM:
1166
0
    proxy_socktype = ISC_PROXY2_SOCK_DGRAM;
1167
0
    break;
1168
0
  default:
1169
0
    return ISC_R_UNEXPECTED;
1170
0
  }
1171
1172
0
  if (tlv_data != NULL) {
1173
0
    if (tlv_data->length > UINT16_MAX) {
1174
0
      return ISC_R_RANGE;
1175
0
    }
1176
0
    total_size += tlv_data->length;
1177
0
  }
1178
1179
0
  if (isc_buffer_availablelength(outbuf) < total_size) {
1180
0
    return ISC_R_NOSPACE;
1181
0
  } else if (total_size > UINT16_MAX) {
1182
0
    return ISC_R_RANGE;
1183
0
  }
1184
1185
  /*
1186
   * Combine version 2 (highest four bits) and command (lowest four
1187
   * bits).
1188
   */
1189
0
  ver_cmd = (((2 << 4) & 0xF0U) | cmd);
1190
1191
  /*
1192
   * Combine address family (highest four bits) and socket type
1193
   * (lowest four bits).
1194
   */
1195
0
  fam_socktype = (((family << 4) & 0xF0U) | proxy_socktype);
1196
1197
0
  len = (uint16_t)(total_size - ISC_PROXY2_HEADER_SIZE);
1198
1199
  /* Write signature */
1200
0
  isc_buffer_putmem(outbuf, (uint8_t *)ISC_PROXY2_HEADER_SIGNATURE,
1201
0
        ISC_PROXY2_HEADER_SIGNATURE_SIZE);
1202
  /* Write version and command */
1203
0
  isc_buffer_putuint8(outbuf, ver_cmd);
1204
  /* Write address family and socket type */
1205
0
  isc_buffer_putuint8(outbuf, fam_socktype);
1206
  /* Write header payload size (addresses + TLVs) */
1207
0
  isc_buffer_putuint16(outbuf, len);
1208
1209
  /* Write source and destination addresses (if we should) */
1210
0
  if (psrc_addr != NULL) {
1211
0
    isc_buffer_putmem(outbuf, psrc_addr, addr_size);
1212
0
  }
1213
1214
0
  if (pdst_addr != NULL) {
1215
0
    isc_buffer_putmem(outbuf, pdst_addr, addr_size);
1216
0
  }
1217
1218
  /* Write source and destination ports (if we should) */
1219
0
  if (family == ISC_PROXY2_AF_INET || family == ISC_PROXY2_AF_INET6) {
1220
0
    isc_buffer_putuint16(outbuf, isc_sockaddr_getport(src_addr));
1221
0
    isc_buffer_putuint16(outbuf, isc_sockaddr_getport(dst_addr));
1222
0
  }
1223
1224
0
  if (tlv_data != NULL) {
1225
0
    isc_buffer_putmem(outbuf, tlv_data->base, tlv_data->length);
1226
0
  }
1227
1228
0
  return ISC_R_SUCCESS;
1229
0
}
1230
1231
isc_result_t
1232
isc_proxy2_header_append(isc_buffer_t *restrict outbuf,
1233
0
       const isc_region_t *restrict data) {
1234
0
  const size_t len_offset = ISC_PROXY2_HEADER_SIZE - sizeof(uint16_t);
1235
0
  isc_region_t header_data = { 0 };
1236
0
  uint16_t new_len = 0;
1237
1238
0
  REQUIRE(outbuf != NULL);
1239
1240
0
  isc_buffer_usedregion(outbuf, &header_data);
1241
1242
0
  REQUIRE(header_data.length >= ISC_PROXY2_HEADER_SIZE);
1243
0
  REQUIRE(data != NULL);
1244
1245
0
  if (isc_buffer_availablelength(outbuf) < data->length) {
1246
0
    return ISC_R_NOSPACE;
1247
0
  } else if ((data->length + header_data.length) > UINT16_MAX) {
1248
0
    return ISC_R_RANGE;
1249
0
  }
1250
1251
0
  INSIST(memcmp(header_data.base, ISC_PROXY2_HEADER_SIGNATURE,
1252
0
          ISC_PROXY2_HEADER_SIGNATURE_SIZE) == 0);
1253
1254
  /* fixup length of the header payload */
1255
  /* load */
1256
0
  memmove(&new_len, &header_data.base[len_offset], sizeof(new_len));
1257
0
  new_len = ntohs(new_len);
1258
  /* check */
1259
0
  if ((data->length + new_len) > UINT16_MAX) {
1260
0
    return ISC_R_RANGE;
1261
0
  }
1262
  /* update */
1263
0
  new_len += (uint16_t)data->length;
1264
  /* store */
1265
0
  new_len = htons(new_len);
1266
0
  memmove(&header_data.base[len_offset], &new_len, sizeof(new_len));
1267
1268
0
  isc_buffer_putmem(outbuf, data->base, data->length);
1269
1270
0
  return ISC_R_SUCCESS;
1271
0
}
1272
1273
static inline void
1274
append_type_and_length(isc_buffer_t *restrict outbuf, const uint8_t type,
1275
0
           const uint16_t tlv_length, const bool update_header) {
1276
0
  uint16_t length;
1277
0
  isc_region_t type_region = { 0 }, length_region = { 0 };
1278
1279
0
  type_region = (isc_region_t){ .base = (uint8_t *)&type,
1280
0
              .length = sizeof(type) };
1281
0
  length = htons(tlv_length);
1282
0
  length_region = (isc_region_t){ .base = (uint8_t *)&length,
1283
0
          .length = sizeof(length) };
1284
1285
0
  if (update_header) {
1286
0
    isc_result_t result = isc_proxy2_header_append(outbuf,
1287
0
                     &type_region);
1288
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
1289
0
    result = isc_proxy2_header_append(outbuf, &length_region);
1290
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
1291
0
  } else {
1292
0
    isc_buffer_putmem(outbuf, type_region.base, type_region.length);
1293
0
    isc_buffer_putmem(outbuf, length_region.base,
1294
0
          length_region.length);
1295
0
  }
1296
0
}
1297
1298
isc_result_t
1299
isc_proxy2_header_append_tlv(isc_buffer_t *restrict outbuf,
1300
           const isc_proxy2_tlv_type_t tlv_type,
1301
0
           const isc_region_t *restrict tlv_data) {
1302
0
  size_t new_data_len = 0;
1303
0
  REQUIRE(outbuf != NULL);
1304
0
  REQUIRE(tlv_data != NULL);
1305
1306
  /*
1307
   * TLV header can be described as follows:
1308
   *
1309
   *   struct {
1310
   *       uint8_t type;
1311
   *       uint8_t length_hi;
1312
   *       uint8_t length_lo;
1313
   *   };
1314
   *
1315
   */
1316
0
  new_data_len = tlv_data->length + 3;
1317
1318
0
  if (isc_buffer_availablelength(outbuf) < (new_data_len)) {
1319
0
    return ISC_R_NOSPACE;
1320
0
  } else if ((isc_buffer_usedlength(outbuf) + new_data_len) > UINT16_MAX)
1321
0
  {
1322
0
    return ISC_R_RANGE;
1323
0
  }
1324
1325
0
  append_type_and_length(outbuf, (uint8_t)tlv_type,
1326
0
             (uint16_t)tlv_data->length, true);
1327
1328
0
  if (tlv_data->length > 0) {
1329
0
    isc_result_t result = isc_proxy2_header_append(outbuf,
1330
0
                     tlv_data);
1331
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
1332
0
  }
1333
1334
0
  return ISC_R_SUCCESS;
1335
0
}
1336
1337
isc_result_t
1338
isc_proxy2_header_append_tlv_string(isc_buffer_t *restrict outbuf,
1339
            const isc_proxy2_tlv_type_t tlv_type,
1340
0
            const char *restrict str) {
1341
0
  isc_result_t result;
1342
0
  isc_region_t region = { 0 };
1343
1344
0
  REQUIRE(str != NULL && *str != '\0');
1345
1346
0
  region.base = (uint8_t *)str;
1347
0
  region.length = strlen(str);
1348
1349
0
  result = isc_proxy2_header_append_tlv(outbuf, tlv_type, &region);
1350
1351
0
  return result;
1352
0
}
1353
1354
isc_result_t
1355
isc_proxy2_make_tls_subheader(isc_buffer_t *restrict outbuf,
1356
            const uint8_t client_flags,
1357
            const bool client_cert_verified,
1358
0
            const isc_region_t *restrict tls_subtlvs_data) {
1359
0
  size_t total_size = ISC_PROXY2_TLS_SUBHEADER_MIN_SIZE;
1360
0
  uint32_t client_cert_not_verified = 1;
1361
0
  REQUIRE(outbuf != NULL);
1362
1363
0
  if (tls_subtlvs_data != NULL) {
1364
0
    total_size += tls_subtlvs_data->length;
1365
0
  }
1366
1367
0
  if (isc_buffer_availablelength(outbuf) < total_size) {
1368
0
    return ISC_R_NOSPACE;
1369
0
  } else if (total_size > UINT16_MAX) {
1370
0
    return ISC_R_RANGE;
1371
0
  }
1372
1373
0
  isc_buffer_putuint8(outbuf, client_flags);
1374
0
  client_cert_not_verified = htonl(!client_cert_verified);
1375
0
  isc_buffer_putmem(outbuf, (uint8_t *)&client_cert_not_verified,
1376
0
        sizeof(client_cert_not_verified));
1377
1378
0
  if (tls_subtlvs_data != NULL) {
1379
0
    isc_buffer_putmem(outbuf, tls_subtlvs_data->base,
1380
0
          tls_subtlvs_data->length);
1381
0
  }
1382
1383
0
  return ISC_R_SUCCESS;
1384
0
}
1385
1386
isc_result_t
1387
isc_proxy2_append_tlv(isc_buffer_t *restrict outbuf, const uint8_t type,
1388
0
          const isc_region_t *restrict data) {
1389
0
  size_t new_data_len = 0;
1390
0
  REQUIRE(outbuf != NULL);
1391
0
  REQUIRE(data != NULL);
1392
1393
0
  new_data_len = (data->length + 3);
1394
1395
0
  if (isc_buffer_availablelength(outbuf) < new_data_len) {
1396
0
    return ISC_R_NOSPACE;
1397
0
  } else if ((isc_buffer_usedlength(outbuf) + (data->length + 3)) >
1398
0
       UINT16_MAX)
1399
0
  {
1400
0
    return ISC_R_RANGE;
1401
0
  }
1402
1403
0
  append_type_and_length(outbuf, (uint8_t)type, (uint16_t)data->length,
1404
0
             false);
1405
1406
0
  if (data->length > 0) {
1407
0
    isc_buffer_putmem(outbuf, data->base, data->length);
1408
0
  }
1409
1410
0
  return ISC_R_SUCCESS;
1411
0
}
1412
1413
isc_result_t
1414
isc_proxy2_append_tlv_string(isc_buffer_t *restrict outbuf, const uint8_t type,
1415
0
           const char *restrict str) {
1416
0
  isc_result_t result;
1417
0
  isc_region_t region = { 0 };
1418
1419
0
  REQUIRE(str != NULL && *str != '\0');
1420
1421
0
  region.base = (uint8_t *)str;
1422
0
  region.length = strlen(str);
1423
1424
0
  result = isc_proxy2_append_tlv(outbuf, type, &region);
1425
1426
0
  return result;
1427
0
}