Coverage Report

Created: 2025-07-18 07:02

/src/bind9/lib/isc/proxy2.c
Line
Count
Source (jump to first uncovered line)
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
  isc_result_t result;
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
  result = isc__proxy2_handler_get_addresses(
697
0
    (isc_proxy2_handler_t *)handler, &buf, psrc_addr, pdst_addr);
698
699
0
  if (result != ISC_R_SUCCESS) {
700
0
    return result;
701
0
  }
702
703
0
  SET_IF_NOT_NULL(psocktype,
704
0
      proxy2_socktype_to_socktype(handler->proxy_socktype));
705
706
0
  return ISC_R_SUCCESS;
707
0
}
708
709
isc_result_t
710
isc_proxy2_tlv_iterate(const isc_region_t *restrict tlv_data,
711
0
           const isc_proxy2_tlv_cb_t cb, void *cbarg) {
712
0
  isc_result_t result = ISC_R_SUCCESS;
713
0
  isc_buffer_t tlvs = { 0 };
714
0
  size_t remaining;
715
716
  /*
717
   * TLV header can be described as follows:
718
   *
719
   *   struct {
720
   *       uint8_t type;
721
   *       uint8_t length_hi;
722
   *       uint8_t length_lo;
723
   *   };
724
   *
725
   */
726
727
0
  REQUIRE(tlv_data != NULL);
728
0
  REQUIRE(cb != NULL);
729
730
0
  isc_buffer_init(&tlvs, tlv_data->base, tlv_data->length);
731
0
  isc_buffer_add(&tlvs, tlv_data->length);
732
733
0
  while ((remaining = isc_buffer_remaininglength(&tlvs)) > 0) {
734
0
    uint8_t type = 0;
735
0
    uint16_t len = 0;
736
0
    isc_region_t current_tlv_data = { 0 };
737
0
    bool ret = false;
738
739
    /* not enough data for a TLV header */
740
0
    if (remaining < ISC_PROXY2_TLV_HEADER_SIZE) {
741
0
      result = ISC_R_RANGE;
742
0
      break;
743
0
    }
744
745
0
    type = isc_buffer_getuint8(&tlvs);
746
0
    len = isc_buffer_getuint16(&tlvs);
747
748
0
    if ((remaining - ISC_PROXY2_TLV_HEADER_SIZE) < len) {
749
0
      result = ISC_R_RANGE;
750
0
      break;
751
0
    }
752
753
0
    current_tlv_data.base = isc_buffer_current(&tlvs);
754
0
    current_tlv_data.length = len;
755
0
    isc_buffer_forward(&tlvs, len);
756
757
0
    ret = cb((isc_proxy2_tlv_type_t)type, &current_tlv_data, cbarg);
758
0
    if (!ret) {
759
0
      break;
760
0
    }
761
0
  }
762
763
0
  return result;
764
0
}
765
766
typedef struct proxy2_tls_cbarg {
767
  uint8_t client;
768
  bool client_cert_verified;
769
  isc_proxy2_tls_subtlv_cb_t cb;
770
  void *cbarg;
771
} tls_cbarg_t;
772
773
static bool
774
proxy2_tls_iter_cb(const isc_proxy2_tlv_type_t tlv_type,
775
0
       const isc_region_t *restrict data, void *cbarg) {
776
0
  bool ret = false;
777
0
  tls_cbarg_t *tls_cbarg = (tls_cbarg_t *)cbarg;
778
779
0
  ret = tls_cbarg->cb(tls_cbarg->client, tls_cbarg->client_cert_verified,
780
0
          (isc_proxy2_tlv_subtype_tls_t)tlv_type, data,
781
0
          tls_cbarg->cbarg);
782
783
0
  return ret;
784
0
}
785
786
isc_result_t
787
isc_proxy2_subtlv_tls_header_data(const isc_region_t *restrict tls_tlv_data,
788
          uint8_t *restrict pclient_flags,
789
0
          bool *restrict pclient_cert_verified) {
790
  /*
791
   * SSL/TLS TLV header can be described as follows:
792
   *
793
   *   struct {
794
   *       uint8_t  client_flags;
795
   *       uint32_t client_cert_not_verified;
796
   *   }
797
   */
798
0
  uint8_t *p = NULL;
799
0
  uint8_t client_flags = 0;
800
0
  bool client_cert_verified = false;
801
0
  uint32_t client_cert_verified_data = 0;
802
803
0
  REQUIRE(tls_tlv_data != NULL);
804
0
  REQUIRE(pclient_flags == NULL || *pclient_flags == 0);
805
0
  REQUIRE(pclient_cert_verified == NULL ||
806
0
    *pclient_cert_verified == false);
807
808
0
  if (tls_tlv_data->length < ISC_PROXY2_TLS_SUBHEADER_MIN_SIZE) {
809
0
    return ISC_R_RANGE;
810
0
  }
811
812
0
  p = tls_tlv_data->base;
813
814
0
  client_flags = *p;
815
0
  p++;
816
  /* We need this to avoid ASAN complain about unaligned access */
817
0
  memmove(&client_cert_verified_data, p, sizeof(uint32_t));
818
0
  client_cert_verified = ntohl(client_cert_verified_data) == 0;
819
820
0
  SET_IF_NOT_NULL(pclient_flags, client_flags);
821
0
  SET_IF_NOT_NULL(pclient_cert_verified, client_cert_verified);
822
823
0
  return ISC_R_SUCCESS;
824
0
}
825
826
isc_result_t
827
isc_proxy2_subtlv_tls_iterate(const isc_region_t *restrict tls_tlv_data,
828
            const isc_proxy2_tls_subtlv_cb_t cb,
829
0
            void *cbarg) {
830
0
  tls_cbarg_t tls_cbarg;
831
0
  isc_result_t result = ISC_R_SUCCESS;
832
0
  uint8_t *p = NULL;
833
0
  uint8_t client_flags = 0;
834
0
  bool client_cert_verified = false;
835
836
0
  REQUIRE(tls_tlv_data != NULL);
837
0
  REQUIRE(cb != NULL);
838
839
0
  if (tls_tlv_data->length < ISC_PROXY2_TLS_SUBHEADER_MIN_SIZE) {
840
0
    return ISC_R_RANGE;
841
0
  }
842
843
0
  result = isc_proxy2_subtlv_tls_header_data(tls_tlv_data, &client_flags,
844
0
               &client_cert_verified);
845
846
0
  if (result != ISC_R_SUCCESS) {
847
0
    return result;
848
0
  }
849
850
0
  p = tls_tlv_data->base;
851
0
  p += ISC_PROXY2_TLS_SUBHEADER_MIN_SIZE;
852
853
0
  if (cb != NULL) {
854
0
    isc_region_t data = {
855
0
      .base = p,
856
0
      .length = tls_tlv_data->length -
857
0
          ISC_PROXY2_TLS_SUBHEADER_MIN_SIZE
858
0
    };
859
0
    tls_cbarg = (tls_cbarg_t){ .client = client_flags,
860
0
             .client_cert_verified =
861
0
               client_cert_verified,
862
0
             .cb = cb,
863
0
             .cbarg = cbarg };
864
0
    result = isc_proxy2_tlv_iterate(&data, proxy2_tls_iter_cb,
865
0
            &tls_cbarg);
866
0
  }
867
868
0
  return result;
869
0
}
870
871
typedef struct tls_subtlv_verify_cbarg {
872
  uint16_t *count;
873
  isc_result_t verif_result;
874
} tls_subtlv_verify_cbarg_t;
875
876
static bool
877
proxy2_subtlv_verify_iter_cb(const uint8_t client,
878
           const bool client_cert_verified,
879
           const isc_proxy2_tlv_subtype_tls_t tls_subtlv_type,
880
0
           const isc_region_t *restrict data, void *cbarg) {
881
0
  bool verify_count = false;
882
0
  tls_subtlv_verify_cbarg_t *restrict arg =
883
0
    (tls_subtlv_verify_cbarg_t *)cbarg;
884
0
  uint8_t type = tls_subtlv_type;
885
886
0
  UNUSED(client);
887
0
  UNUSED(client_cert_verified);
888
889
0
  if (type <= ISC_PROXY2_TLV_TYPE_TLS ||
890
0
      type == ISC_PROXY2_TLV_TYPE_NETNS)
891
0
  {
892
0
    arg->verif_result = ISC_R_UNEXPECTED;
893
0
    return false;
894
0
  }
895
896
0
  switch (tls_subtlv_type) {
897
0
  case ISC_PROXY2_TLV_SUBTYPE_TLS_VERSION:
898
0
  case ISC_PROXY2_TLV_SUBTYPE_TLS_CN:
899
0
  case ISC_PROXY2_TLV_SUBTYPE_TLS_SIG_ALG:
900
0
  case ISC_PROXY2_TLV_SUBTYPE_TLS_KEY_ALG:
901
0
    if (data->length == 0) {
902
0
      arg->verif_result = ISC_R_RANGE;
903
0
      return false;
904
0
    }
905
0
    arg->count[tls_subtlv_type]++;
906
0
    verify_count = true;
907
0
    break;
908
0
  default:
909
0
    break;
910
0
  };
911
912
0
  if (verify_count && arg->count[tls_subtlv_type] > 1) {
913
0
    arg->verif_result = ISC_R_UNEXPECTED;
914
0
    return false;
915
0
  }
916
917
0
  return true;
918
0
}
919
920
typedef struct tlv_verify_cbarg {
921
  uint16_t count[256];
922
  isc_result_t verify_result;
923
} tlv_verify_cbarg_t;
924
925
static bool
926
isc_proxy2_tlv_verify_cb(const isc_proxy2_tlv_type_t tlv_type,
927
0
       const isc_region_t *restrict data, void *cbarg) {
928
0
  bool verify_count = false;
929
0
  uint8_t client = 0;
930
0
  tlv_verify_cbarg_t *arg = (tlv_verify_cbarg_t *)cbarg;
931
932
0
  if (tlv_type == 0) {
933
    /* the TLV values start from 1 */
934
0
    goto error_unexpected;
935
0
  }
936
937
0
  switch (tlv_type) {
938
0
  case ISC_PROXY2_TLV_TYPE_ALPN:
939
0
  case ISC_PROXY2_TLV_TYPE_AUTHORITY:
940
0
  case ISC_PROXY2_TLV_TYPE_NETNS:
941
    /* these values need to be more than 0 bytes long */
942
0
    if (data->length == 0) {
943
0
      goto error_range;
944
0
    }
945
0
    arg->count[tlv_type]++;
946
0
    verify_count = true;
947
0
    break;
948
0
  case ISC_PROXY2_TLV_TYPE_CRC32C:
949
0
    if (data->length != sizeof(uint32_t)) {
950
0
      goto error_range;
951
0
    }
952
0
    arg->count[tlv_type]++;
953
0
    verify_count = true;
954
0
    break;
955
0
  case ISC_PROXY2_TLV_TYPE_UNIQUE_ID:
956
0
    if (data->length > 128) {
957
0
      goto error_range;
958
0
    }
959
0
    arg->count[tlv_type]++;
960
0
    verify_count = true;
961
0
    break;
962
0
  case ISC_PROXY2_TLV_TYPE_TLS: {
963
0
    tls_subtlv_verify_cbarg_t tls_cbarg = {
964
0
      .verif_result = ISC_R_SUCCESS, .count = arg->count
965
0
    };
966
0
    size_t tls_version_count, tls_cn_count;
967
968
0
    arg->verify_result =
969
0
      isc_proxy2_subtlv_tls_header_data(data, &client, NULL);
970
971
0
    if (arg->verify_result != ISC_R_SUCCESS) {
972
0
      return false;
973
0
    }
974
975
0
    arg->verify_result = isc_proxy2_subtlv_tls_iterate(
976
0
      data, proxy2_subtlv_verify_iter_cb, &tls_cbarg);
977
978
0
    if (arg->verify_result != ISC_R_SUCCESS) {
979
0
      return false;
980
0
    } else if (tls_cbarg.verif_result != ISC_R_SUCCESS) {
981
0
      arg->verify_result = tls_cbarg.verif_result;
982
0
      return false;
983
0
    }
984
985
    /*
986
     * if CLIENT_TLS flag is set - TLS version TLV must be present
987
     */
988
0
    tls_version_count =
989
0
      arg->count[ISC_PROXY2_TLV_SUBTYPE_TLS_VERSION];
990
991
0
    if ((client & ISC_PROXY2_CLIENT_TLS) != 0) {
992
0
      if (tls_version_count != 1) {
993
0
        goto error_unexpected;
994
0
      }
995
0
    } else if (tls_version_count > 0) {
996
      /* unexpected TLS version TLV */
997
0
      goto error_unexpected;
998
0
    }
999
1000
    /*
1001
     * If client cert was submitted, CLIENT_CERT_CONN or
1002
     * CLIENT_CERT_SESS flags must be present alongside the
1003
     * CLIENT_TLS flag.
1004
     */
1005
0
    tls_cn_count = arg->count[ISC_PROXY2_TLV_SUBTYPE_TLS_CN];
1006
1007
0
    if ((client & (ISC_PROXY2_CLIENT_CERT_CONN |
1008
0
             ISC_PROXY2_CLIENT_CERT_SESS)) != 0)
1009
0
    {
1010
0
      if (tls_cn_count != 1 ||
1011
0
          (client & ISC_PROXY2_CLIENT_TLS) == 0)
1012
0
      {
1013
0
        goto error_unexpected;
1014
0
      }
1015
0
    } else if (tls_cn_count > 0) {
1016
      /* unexpected Common Name TLV */
1017
0
      goto error_unexpected;
1018
0
    }
1019
1020
0
    arg->count[tlv_type]++;
1021
0
    verify_count = true;
1022
0
  } break;
1023
0
  default:
1024
0
    break;
1025
0
  };
1026
1027
0
  if (verify_count && arg->count[tlv_type] > 1) {
1028
0
    goto error_unexpected;
1029
0
  }
1030
1031
0
  return true;
1032
1033
0
error_unexpected:
1034
0
  arg->verify_result = ISC_R_UNEXPECTED;
1035
0
  return false;
1036
1037
0
error_range:
1038
0
  arg->verify_result = ISC_R_RANGE;
1039
0
  return false;
1040
0
}
1041
1042
isc_result_t
1043
0
isc_proxy2_tlv_data_verify(const isc_region_t *restrict tlv_data) {
1044
0
  isc_result_t result;
1045
0
  tlv_verify_cbarg_t cbarg = { .verify_result = ISC_R_SUCCESS };
1046
1047
0
  result = isc_proxy2_tlv_iterate(tlv_data, isc_proxy2_tlv_verify_cb,
1048
0
          &cbarg);
1049
0
  if (result != ISC_R_SUCCESS) {
1050
0
    return result;
1051
0
  }
1052
1053
0
  return cbarg.verify_result;
1054
0
}
1055
1056
isc_result_t
1057
isc_proxy2_header_handle_directly(const isc_region_t *restrict header_data,
1058
          const isc_proxy2_handler_cb_t cb,
1059
0
          void *cbarg) {
1060
0
  isc_result_t result;
1061
0
  isc_proxy2_handler_t handler = { 0 };
1062
1063
0
  REQUIRE(header_data != NULL);
1064
0
  REQUIRE(cb != NULL);
1065
1066
0
  isc__proxy2_handler_init_direct(&handler, 0, header_data, cb, cbarg);
1067
1068
0
  result = isc__proxy2_handler_process_data(&handler);
1069
1070
0
  return result;
1071
0
}
1072
1073
isc_result_t
1074
isc_proxy2_make_header(isc_buffer_t *restrict outbuf,
1075
           const isc_proxy2_command_t cmd, const int socktype,
1076
           const isc_sockaddr_t *restrict src_addr,
1077
           const isc_sockaddr_t *restrict dst_addr,
1078
0
           const isc_region_t *restrict tlv_data) {
1079
0
  size_t total_size = ISC_PROXY2_HEADER_SIZE;
1080
0
  uint8_t family = ISC_PROXY2_AF_UNSPEC;
1081
0
  isc_proxy2_socktype_t proxy_socktype = ISC_PROXY2_SOCK_UNSPEC;
1082
1083
0
  uint8_t ver_cmd = 0;
1084
0
  uint8_t fam_socktype = 0;
1085
0
  uint16_t len = 0;
1086
1087
0
  size_t addr_size = 0;
1088
0
  void *psrc_addr = NULL, *pdst_addr = NULL;
1089
  /*
1090
   * The complete PROXYv2 header can be described as follows:
1091
   *
1092
   * 1. Header:
1093
   *
1094
   * struct proxy_hdr_v2 {
1095
   *   uint8_t sig[12];      // hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A
1096
   *   uint8_t ver_cmd;      // protocol version and command
1097
   *   uint8_t fam_socktype; // protocol family and socket type
1098
   *   uint16_t len;         // number of following bytes
1099
   * };
1100
   *
1101
   * 2. Addresses:
1102
   *
1103
   * union proxy_addr {
1104
   *   struct {        // for TCP/UDP over IPv4, len = 12
1105
   *       uint32_t src_addr;
1106
   *       uint32_t dst_addr;
1107
   *       uint16_t src_port;
1108
   *       uint16_t dst_port;
1109
   *   } ipv4_addr;
1110
   *   struct {        // for TCP/UDP over IPv6, len = 36
1111
   *        uint8_t  src_addr[16];
1112
   *        uint8_t  dst_addr[16];
1113
   *        uint16_t src_port;
1114
   *        uint16_t dst_port;
1115
   *   } ipv6_addr;
1116
   *   struct {        // for AF_UNIX sockets, len = 216
1117
   *        uint8_t src_addr[108];
1118
   *        uint8_t dst_addr[108];
1119
   *   } unix_addr;
1120
   * };
1121
   *
1122
   * 3. TLVs (optional)
1123
   */
1124
1125
0
  REQUIRE(outbuf != NULL);
1126
0
  REQUIRE(cmd == ISC_PROXY2_CMD_PROXY || socktype == 0);
1127
0
  REQUIRE((src_addr == NULL && dst_addr == NULL) ||
1128
0
    (src_addr != NULL && dst_addr != NULL));
1129
0
  REQUIRE(src_addr == NULL ||
1130
0
    (isc_sockaddr_pf(src_addr) == isc_sockaddr_pf(dst_addr)));
1131
1132
0
  switch (cmd) {
1133
0
  case ISC_PROXY2_CMD_LOCAL:
1134
0
    family = ISC_PROXY2_AF_UNSPEC;
1135
0
    break;
1136
0
  case ISC_PROXY2_CMD_PROXY:
1137
0
    if (socktype == 0) {
1138
0
      family = ISC_PROXY2_AF_UNSPEC;
1139
0
    } else {
1140
0
      switch (isc_sockaddr_pf(src_addr)) {
1141
0
      case AF_INET:
1142
0
        family = ISC_PROXY2_AF_INET;
1143
0
        addr_size = sizeof(src_addr->type.sin.sin_addr);
1144
0
        total_size += addr_size * 2 +
1145
0
                sizeof(uint16_t) * 2;
1146
0
        psrc_addr = (void *)&src_addr->type.sin.sin_addr
1147
0
                .s_addr;
1148
0
        pdst_addr = (void *)&dst_addr->type.sin.sin_addr
1149
0
                .s_addr;
1150
0
        break;
1151
0
      case AF_INET6:
1152
0
        family = ISC_PROXY2_AF_INET6;
1153
0
        addr_size =
1154
0
          sizeof(src_addr->type.sin6.sin6_addr);
1155
0
        total_size += addr_size * 2 +
1156
0
                sizeof(uint16_t) * 2;
1157
0
        psrc_addr =
1158
0
          (void *)&src_addr->type.sin6.sin6_addr;
1159
0
        pdst_addr =
1160
0
          (void *)&dst_addr->type.sin6.sin6_addr;
1161
0
        break;
1162
0
      default:
1163
0
        return ISC_R_UNEXPECTED;
1164
0
      }
1165
0
    }
1166
0
    break;
1167
0
  default:
1168
0
    return ISC_R_UNEXPECTED;
1169
0
  }
1170
1171
0
  switch (socktype) {
1172
0
  case 0:
1173
0
    proxy_socktype = ISC_PROXY2_SOCK_UNSPEC;
1174
0
    break;
1175
0
  case SOCK_STREAM:
1176
0
    proxy_socktype = ISC_PROXY2_SOCK_STREAM;
1177
0
    break;
1178
0
  case SOCK_DGRAM:
1179
0
    proxy_socktype = ISC_PROXY2_SOCK_DGRAM;
1180
0
    break;
1181
0
  default:
1182
0
    return ISC_R_UNEXPECTED;
1183
0
  }
1184
1185
0
  if (tlv_data != NULL) {
1186
0
    if (tlv_data->length > UINT16_MAX) {
1187
0
      return ISC_R_RANGE;
1188
0
    }
1189
0
    total_size += tlv_data->length;
1190
0
  }
1191
1192
0
  if (isc_buffer_availablelength(outbuf) < total_size) {
1193
0
    return ISC_R_NOSPACE;
1194
0
  } else if (total_size > UINT16_MAX) {
1195
0
    return ISC_R_RANGE;
1196
0
  }
1197
1198
  /*
1199
   * Combine version 2 (highest four bits) and command (lowest four
1200
   * bits).
1201
   */
1202
0
  ver_cmd = (((2 << 4) & 0xF0U) | cmd);
1203
1204
  /*
1205
   * Combine address family (highest four bits) and socket type
1206
   * (lowest four bits).
1207
   */
1208
0
  fam_socktype = (((family << 4) & 0xF0U) | proxy_socktype);
1209
1210
0
  len = (uint16_t)(total_size - ISC_PROXY2_HEADER_SIZE);
1211
1212
  /* Write signature */
1213
0
  isc_buffer_putmem(outbuf, (uint8_t *)ISC_PROXY2_HEADER_SIGNATURE,
1214
0
        ISC_PROXY2_HEADER_SIGNATURE_SIZE);
1215
  /* Write version and command */
1216
0
  isc_buffer_putuint8(outbuf, ver_cmd);
1217
  /* Write address family and socket type */
1218
0
  isc_buffer_putuint8(outbuf, fam_socktype);
1219
  /* Write header payload size (addresses + TLVs) */
1220
0
  isc_buffer_putuint16(outbuf, len);
1221
1222
  /* Write source and destination addresses (if we should) */
1223
0
  if (psrc_addr != NULL) {
1224
0
    isc_buffer_putmem(outbuf, psrc_addr, addr_size);
1225
0
  }
1226
1227
0
  if (pdst_addr != NULL) {
1228
0
    isc_buffer_putmem(outbuf, pdst_addr, addr_size);
1229
0
  }
1230
1231
  /* Write source and destination ports (if we should) */
1232
0
  if (family == ISC_PROXY2_AF_INET || family == ISC_PROXY2_AF_INET6) {
1233
0
    isc_buffer_putuint16(outbuf, isc_sockaddr_getport(src_addr));
1234
0
    isc_buffer_putuint16(outbuf, isc_sockaddr_getport(dst_addr));
1235
0
  }
1236
1237
0
  if (tlv_data != NULL) {
1238
0
    isc_buffer_putmem(outbuf, tlv_data->base, tlv_data->length);
1239
0
  }
1240
1241
0
  return ISC_R_SUCCESS;
1242
0
}
1243
1244
isc_result_t
1245
isc_proxy2_header_append(isc_buffer_t *restrict outbuf,
1246
0
       const isc_region_t *restrict data) {
1247
0
  const size_t len_offset = ISC_PROXY2_HEADER_SIZE - sizeof(uint16_t);
1248
0
  isc_region_t header_data = { 0 };
1249
0
  uint16_t new_len = 0;
1250
1251
0
  REQUIRE(outbuf != NULL);
1252
1253
0
  isc_buffer_usedregion(outbuf, &header_data);
1254
1255
0
  REQUIRE(header_data.length >= ISC_PROXY2_HEADER_SIZE);
1256
0
  REQUIRE(data != NULL);
1257
1258
0
  if (isc_buffer_availablelength(outbuf) < data->length) {
1259
0
    return ISC_R_NOSPACE;
1260
0
  } else if ((data->length + header_data.length) > UINT16_MAX) {
1261
0
    return ISC_R_RANGE;
1262
0
  }
1263
1264
0
  INSIST(memcmp(header_data.base, ISC_PROXY2_HEADER_SIGNATURE,
1265
0
          ISC_PROXY2_HEADER_SIGNATURE_SIZE) == 0);
1266
1267
  /* fixup length of the header payload */
1268
  /* load */
1269
0
  memmove(&new_len, &header_data.base[len_offset], sizeof(new_len));
1270
0
  new_len = ntohs(new_len);
1271
  /* check */
1272
0
  if ((data->length + new_len) > UINT16_MAX) {
1273
0
    return ISC_R_RANGE;
1274
0
  }
1275
  /* update */
1276
0
  new_len += (uint16_t)data->length;
1277
  /* store */
1278
0
  new_len = htons(new_len);
1279
0
  memmove(&header_data.base[len_offset], &new_len, sizeof(new_len));
1280
1281
0
  isc_buffer_putmem(outbuf, data->base, data->length);
1282
1283
0
  return ISC_R_SUCCESS;
1284
0
}
1285
1286
static inline void
1287
append_type_and_length(isc_buffer_t *restrict outbuf, const uint8_t type,
1288
0
           const uint16_t tlv_length, const bool update_header) {
1289
0
  uint16_t length;
1290
0
  isc_region_t type_region = { 0 }, length_region = { 0 };
1291
1292
0
  type_region = (isc_region_t){ .base = (uint8_t *)&type,
1293
0
              .length = sizeof(type) };
1294
0
  length = htons(tlv_length);
1295
0
  length_region = (isc_region_t){ .base = (uint8_t *)&length,
1296
0
          .length = sizeof(length) };
1297
1298
0
  if (update_header) {
1299
0
    isc_result_t result = isc_proxy2_header_append(outbuf,
1300
0
                     &type_region);
1301
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
1302
0
    result = isc_proxy2_header_append(outbuf, &length_region);
1303
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
1304
0
  } else {
1305
0
    isc_buffer_putmem(outbuf, type_region.base, type_region.length);
1306
0
    isc_buffer_putmem(outbuf, length_region.base,
1307
0
          length_region.length);
1308
0
  }
1309
0
}
1310
1311
isc_result_t
1312
isc_proxy2_header_append_tlv(isc_buffer_t *restrict outbuf,
1313
           const isc_proxy2_tlv_type_t tlv_type,
1314
0
           const isc_region_t *restrict tlv_data) {
1315
0
  size_t new_data_len = 0;
1316
0
  REQUIRE(outbuf != NULL);
1317
0
  REQUIRE(tlv_data != NULL);
1318
1319
  /*
1320
   * TLV header can be described as follows:
1321
   *
1322
   *   struct {
1323
   *       uint8_t type;
1324
   *       uint8_t length_hi;
1325
   *       uint8_t length_lo;
1326
   *   };
1327
   *
1328
   */
1329
0
  new_data_len = tlv_data->length + 3;
1330
1331
0
  if (isc_buffer_availablelength(outbuf) < (new_data_len)) {
1332
0
    return ISC_R_NOSPACE;
1333
0
  } else if ((isc_buffer_usedlength(outbuf) + new_data_len) > UINT16_MAX)
1334
0
  {
1335
0
    return ISC_R_RANGE;
1336
0
  }
1337
1338
0
  append_type_and_length(outbuf, (uint8_t)tlv_type,
1339
0
             (uint16_t)tlv_data->length, true);
1340
1341
0
  if (tlv_data->length > 0) {
1342
0
    isc_result_t result = isc_proxy2_header_append(outbuf,
1343
0
                     tlv_data);
1344
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
1345
0
  }
1346
1347
0
  return ISC_R_SUCCESS;
1348
0
}
1349
1350
isc_result_t
1351
isc_proxy2_header_append_tlv_string(isc_buffer_t *restrict outbuf,
1352
            const isc_proxy2_tlv_type_t tlv_type,
1353
0
            const char *restrict str) {
1354
0
  isc_result_t result;
1355
0
  isc_region_t region = { 0 };
1356
1357
0
  REQUIRE(str != NULL && *str != '\0');
1358
1359
0
  region.base = (uint8_t *)str;
1360
0
  region.length = strlen(str);
1361
1362
0
  result = isc_proxy2_header_append_tlv(outbuf, tlv_type, &region);
1363
1364
0
  return result;
1365
0
}
1366
1367
isc_result_t
1368
isc_proxy2_make_tls_subheader(isc_buffer_t *restrict outbuf,
1369
            const uint8_t client_flags,
1370
            const bool client_cert_verified,
1371
0
            const isc_region_t *restrict tls_subtlvs_data) {
1372
0
  size_t total_size = ISC_PROXY2_TLS_SUBHEADER_MIN_SIZE;
1373
0
  uint32_t client_cert_not_verified = 1;
1374
0
  REQUIRE(outbuf != NULL);
1375
1376
0
  if (tls_subtlvs_data != NULL) {
1377
0
    total_size += tls_subtlvs_data->length;
1378
0
  }
1379
1380
0
  if (isc_buffer_availablelength(outbuf) < total_size) {
1381
0
    return ISC_R_NOSPACE;
1382
0
  } else if (total_size > UINT16_MAX) {
1383
0
    return ISC_R_RANGE;
1384
0
  }
1385
1386
0
  isc_buffer_putuint8(outbuf, client_flags);
1387
0
  client_cert_not_verified = htonl(!client_cert_verified);
1388
0
  isc_buffer_putmem(outbuf, (uint8_t *)&client_cert_not_verified,
1389
0
        sizeof(client_cert_not_verified));
1390
1391
0
  if (tls_subtlvs_data != NULL) {
1392
0
    isc_buffer_putmem(outbuf, tls_subtlvs_data->base,
1393
0
          tls_subtlvs_data->length);
1394
0
  }
1395
1396
0
  return ISC_R_SUCCESS;
1397
0
}
1398
1399
isc_result_t
1400
isc_proxy2_append_tlv(isc_buffer_t *restrict outbuf, const uint8_t type,
1401
0
          const isc_region_t *restrict data) {
1402
0
  size_t new_data_len = 0;
1403
0
  REQUIRE(outbuf != NULL);
1404
0
  REQUIRE(data != NULL);
1405
1406
0
  new_data_len = (data->length + 3);
1407
1408
0
  if (isc_buffer_availablelength(outbuf) < new_data_len) {
1409
0
    return ISC_R_NOSPACE;
1410
0
  } else if ((isc_buffer_usedlength(outbuf) + (data->length + 3)) >
1411
0
       UINT16_MAX)
1412
0
  {
1413
0
    return ISC_R_RANGE;
1414
0
  }
1415
1416
0
  append_type_and_length(outbuf, (uint8_t)type, (uint16_t)data->length,
1417
0
             false);
1418
1419
0
  if (data->length > 0) {
1420
0
    isc_buffer_putmem(outbuf, data->base, data->length);
1421
0
  }
1422
1423
0
  return ISC_R_SUCCESS;
1424
0
}
1425
1426
isc_result_t
1427
isc_proxy2_append_tlv_string(isc_buffer_t *restrict outbuf, const uint8_t type,
1428
0
           const char *restrict str) {
1429
0
  isc_result_t result;
1430
0
  isc_region_t region = { 0 };
1431
1432
0
  REQUIRE(str != NULL && *str != '\0');
1433
1434
0
  region.base = (uint8_t *)str;
1435
0
  region.length = strlen(str);
1436
1437
0
  result = isc_proxy2_append_tlv(outbuf, type, &region);
1438
1439
0
  return result;
1440
0
}