Coverage Report

Created: 2026-08-13 07:07

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