Coverage Report

Created: 2026-09-01 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensips/net/proxy_protocol.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2025 OpenSIPS Solutions
3
 *
4
 * This file is part of opensips, a free SIP server.
5
 *
6
 * opensips is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 2 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * opensips is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
 *
20
 */
21
22
#include <stdlib.h>
23
#include <string.h>
24
#include <stdio.h>
25
#include "proxy_protocol.h"
26
#include "../socket_info.h"
27
#include "tcp_conn_defs.h"
28
#include "tcp_common.h"
29
#include "../ut.h"
30
#include "../tsend.h"
31
32
0
#define PROXY_PROTOCOL_V1_HDR "PROXY "
33
0
#define PROXY_PROTOCOL_V1_HDR_LEN (sizeof(PROXY_PROTOCOL_V1_HDR) - 1)
34
0
#define PROXY_PROTOCOL_V1_UNKN "PROXY UNKNOWN\r\n"
35
0
#define PROXY_PROTOCOL_V1_UNKN_LEN (sizeof(PROXY_PROTOCOL_V1_UNKN) - 1)
36
0
#define PROXY_PROTOCOL_TCP4 "TCP4 "
37
0
#define PROXY_PROTOCOL_TCP4_LEN (sizeof(PROXY_PROTOCOL_TCP4) - 1)
38
0
#define PROXY_PROTOCOL_TCP6 "TCP6 "
39
0
#define PROXY_PROTOCOL_TCP6_LEN (sizeof(PROXY_PROTOCOL_TCP6) - 1)
40
0
#define PROXY_PROTOCOL_UNKN "UNKNOWN"
41
0
#define PROXY_PROTOCOL_UNKN_LEN (sizeof(PROXY_PROTOCOL_UNKN) - 1)
42
0
#define PROXY_PROTOCOL_END "\r\n"
43
0
#define PROXY_PROTOCOL_END_LEN (sizeof(PROXY_PROTOCOL_END) - 1)
44
0
#define PROXY_PROTOCOL_SEP ' '
45
/*
46
 * these are defined in the specs:
47
 * https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
48
 */
49
0
#define PROXY_PROTOCOL_TCP4_MAX 56
50
#define PROXY_PROTOCOL_TCP4_PAYLOAD_MAX \
51
0
  (PROXY_PROTOCOL_TCP4_MAX - PROXY_PROTOCOL_V1_HDR_LEN - PROXY_PROTOCOL_TCP4_LEN)
52
0
#define PROXY_PROTOCOL_TCP6_MAX 104
53
#define PROXY_PROTOCOL_TCP6_PAYLOAD_MAX \
54
0
  (PROXY_PROTOCOL_TCP6_MAX - PROXY_PROTOCOL_V1_HDR_LEN - PROXY_PROTOCOL_TCP6_LEN)
55
0
#define PROXY_PROTOCOL_UNKN_MAX PROXY_PROTOCOL_BUF_MAX
56
#define PROXY_PROTOCOL_UNKN_PAYLOAD_MAX \
57
0
  (PROXY_PROTOCOL_UNKN_MAX - PROXY_PROTOCOL_V1_HDR_LEN - PROXY_PROTOCOL_UNKN_LEN)
58
59
enum proxy_tok_match {
60
  PP_TOK_MISMATCH = -1,
61
  PP_TOK_PARTIAL = 0,
62
  PP_TOK_MATCH = 1,
63
};
64
65
static inline enum proxy_tok_match match_proxy_token(const str *buf,
66
    const char *tok, int tok_len)
67
0
{
68
0
  int cmp_len;
69
70
0
  cmp_len = (buf->len < tok_len) ? buf->len : tok_len;
71
0
  if (strncasecmp(buf->s, tok, cmp_len) != 0)
72
0
    return PP_TOK_MISMATCH;
73
0
  if (buf->len < tok_len)
74
0
    return PP_TOK_PARTIAL;
75
0
  return PP_TOK_MATCH;
76
0
}
77
78
int is_net_proxy_protocol(char *buf, int size)
79
0
{
80
0
  if (size < PROXY_PROTOCOL_V1_HDR_LEN)
81
0
    return -1; /* don't know yet */
82
0
  if (memcmp(buf, PROXY_PROTOCOL_V1_HDR, PROXY_PROTOCOL_V1_HDR_LEN))
83
0
    return 0;
84
  /* TODO: support v2 as well? */
85
0
  return 1;
86
0
}
87
88
static int build_proxy_protocol_v1_hdr(const struct ip_addr *src_ip,
89
    unsigned short src_port, const struct ip_addr *dst_ip,
90
    unsigned short dst_port, char *buf, int size)
91
0
{
92
0
  const char *src_s, *dst_s, *proto;
93
0
  int len;
94
95
0
  if (!src_ip || !dst_ip || !buf || size <= 0)
96
0
    return -1;
97
98
0
  if (src_ip->af != dst_ip->af ||
99
0
      (src_ip->af != AF_INET && src_ip->af != AF_INET6)) {
100
0
    if (size < PROXY_PROTOCOL_V1_UNKN_LEN + 1)
101
0
      return -1;
102
0
    memcpy(buf, PROXY_PROTOCOL_V1_UNKN, PROXY_PROTOCOL_V1_UNKN_LEN + 1);
103
0
    return PROXY_PROTOCOL_V1_UNKN_LEN;
104
0
  }
105
106
0
  src_s = ip_addr2a((struct ip_addr *)src_ip);
107
0
  dst_s = ip_addr2a((struct ip_addr *)dst_ip);
108
0
  proto = (src_ip->af == AF_INET) ? "TCP4" : "TCP6";
109
0
  len = snprintf(buf, size, "PROXY %s %s %s %hu %hu\r\n",
110
0
      proto, src_s, dst_s, src_port, dst_port);
111
0
  if (len <= 0 || len >= size)
112
0
    return -1;
113
114
0
  return len;
115
0
}
116
117
int build_outbound_proxy_protocol_v1_hdr(const struct receive_info *ri,
118
    const struct ip_addr *fallback_src_ip,
119
    unsigned short fallback_src_port,
120
    const struct ip_addr *fallback_dst_ip,
121
    unsigned short fallback_dst_port,
122
    char *buf, int size)
123
0
{
124
0
  const struct ip_addr *src_ip = fallback_src_ip;
125
0
  const struct ip_addr *dst_ip = fallback_dst_ip;
126
0
  unsigned short src_port = fallback_src_port;
127
0
  unsigned short dst_port = fallback_dst_port;
128
129
0
  if (ri) {
130
0
    if (ri->real_ep.flags == PP_OK) {
131
0
      src_ip = &ri->real_ep.src_ip;
132
0
      src_port = ri->real_ep.src_port;
133
0
      dst_ip = &ri->real_ep.dst_ip;
134
0
      dst_port = ri->real_ep.dst_port;
135
0
    } else {
136
0
      src_ip = &ri->src_ip;
137
0
      src_port = ri->src_port;
138
0
      dst_ip = &ri->dst_ip;
139
0
      dst_port = ri->dst_port;
140
0
    }
141
0
  }
142
143
0
  return build_proxy_protocol_v1_hdr(src_ip, src_port, dst_ip, dst_port,
144
0
      buf, size);
145
0
}
146
147
static inline int should_send_stream_proxy_protocol(const struct tcp_connection *c)
148
0
{
149
0
  return c && c->rcv.bind_address &&
150
0
    (c->flags & F_CONN_ACCEPTED) == 0 &&
151
0
    (c->rcv.bind_address->flags & SI_PROXY_OUT) &&
152
0
    (c->flags & F_CONN_PROXY_OUT_SENT) == 0;
153
0
}
154
155
int send_stream_proxy_protocol_v1(struct tcp_connection *c, int fd,
156
    int write_timeout, int lock, const struct receive_info *ri,
157
    const char *proto_name)
158
0
{
159
0
  char pp_hdr[PROXY_PROTOCOL_BUF_MAX];
160
0
  int pp_len, rc, dbg_len;
161
0
  const char *action;
162
163
0
  if (!should_send_stream_proxy_protocol(c))
164
0
    return 0;
165
166
0
  if (fd < 0 && ((c->flags & F_CONN_INIT) == 0 || c->fd < 0))
167
0
    return 0;
168
169
0
  pp_len = build_outbound_proxy_protocol_v1_hdr(ri,
170
0
      &c->rcv.dst_ip, c->rcv.dst_port,
171
0
      &c->rcv.src_ip, c->rcv.src_port,
172
0
      pp_hdr, sizeof(pp_hdr));
173
0
  if (pp_len < 0) {
174
0
    LM_ERR("failed to build outbound PROXY header\n");
175
0
    return -1;
176
0
  }
177
178
0
  dbg_len = pp_len;
179
0
  if (dbg_len >= 2 && pp_hdr[dbg_len - 2] == '\r' &&
180
0
      pp_hdr[dbg_len - 1] == '\n')
181
0
    dbg_len -= 2;
182
183
0
  action = (fd < 0) ? "queueing" : "sending";
184
0
  LM_DBG("%s outbound PROXY header on %s conn %u: %.*s\n",
185
0
      action, proto_name ? proto_name : "stream", c->id,
186
0
      dbg_len, pp_hdr);
187
188
0
  if (fd < 0) {
189
0
    rc = tcp_async_add_chunk(c, pp_hdr, pp_len, lock);
190
0
  } else {
191
0
    if (lock)
192
0
      lock_get(&c->write_lock);
193
0
    rc = tsend_stream(fd, pp_hdr, pp_len, write_timeout);
194
0
    if (lock)
195
0
      lock_release(&c->write_lock);
196
0
    if (rc != pp_len) {
197
0
      LM_ERR("failed to send outbound PROXY header on %s\n",
198
0
          proto_name ? proto_name : "stream");
199
0
      return -1;
200
0
    }
201
0
    tcp_conn_reset_lifetime(c);
202
0
    rc = 0;
203
0
  }
204
205
0
  if (rc < 0) {
206
0
    LM_ERR("failed to send outbound PROXY header on %s\n",
207
0
        proto_name ? proto_name : "stream");
208
0
    return -1;
209
0
  }
210
211
0
  c->flags |= F_CONN_PROXY_OUT_SENT;
212
0
  return 0;
213
0
}
214
215
char *parse_net_proxy_protocol(char *buf, int size, struct proxy_protocol *proxy)
216
0
{
217
0
  int af, max;
218
0
  char *p, *end;
219
0
  str _buf, tmp;
220
0
  struct ip_addr *ip;
221
0
  unsigned int port;
222
0
  enum proxy_tok_match m;
223
224
0
  if (size < PROXY_PROTOCOL_V1_HDR_LEN ||
225
0
      memcmp(buf, PROXY_PROTOCOL_V1_HDR, PROXY_PROTOCOL_V1_HDR_LEN) != 0)
226
0
    goto error;
227
228
0
  _buf.s = buf + PROXY_PROTOCOL_V1_HDR_LEN;
229
0
  _buf.len = size - PROXY_PROTOCOL_V1_HDR_LEN;
230
231
0
  m = match_proxy_token(&_buf, PROXY_PROTOCOL_TCP4, PROXY_PROTOCOL_TCP4_LEN);
232
0
  if (m == PP_TOK_MATCH) {
233
0
    af = AF_INET;
234
0
    _buf.s += PROXY_PROTOCOL_TCP4_LEN;
235
0
    _buf.len -= PROXY_PROTOCOL_TCP4_LEN;
236
0
    if (_buf.len > PROXY_PROTOCOL_TCP4_PAYLOAD_MAX)
237
0
      _buf.len = PROXY_PROTOCOL_TCP4_PAYLOAD_MAX;
238
0
    max = PROXY_PROTOCOL_TCP4_MAX;
239
0
  } else if (m == PP_TOK_PARTIAL) {
240
0
    return NULL;
241
0
  } else {
242
0
    m = match_proxy_token(&_buf, PROXY_PROTOCOL_TCP6, PROXY_PROTOCOL_TCP6_LEN);
243
0
    if (m == PP_TOK_MATCH) {
244
0
      af = AF_INET6;
245
0
      _buf.s += PROXY_PROTOCOL_TCP6_LEN;
246
0
      _buf.len -= PROXY_PROTOCOL_TCP6_LEN;
247
0
      if (_buf.len > PROXY_PROTOCOL_TCP6_PAYLOAD_MAX)
248
0
        _buf.len = PROXY_PROTOCOL_TCP6_PAYLOAD_MAX;
249
0
      max = PROXY_PROTOCOL_TCP6_MAX;
250
0
    } else if (m == PP_TOK_PARTIAL) {
251
0
      return NULL;
252
0
    } else {
253
0
      m = match_proxy_token(&_buf, PROXY_PROTOCOL_UNKN, PROXY_PROTOCOL_UNKN_LEN);
254
0
      if (m == PP_TOK_MATCH) {
255
0
        _buf.s += PROXY_PROTOCOL_UNKN_LEN;
256
0
        _buf.len -= PROXY_PROTOCOL_UNKN_LEN;
257
0
        if (_buf.len == 0)
258
0
          return NULL;
259
0
        if (_buf.s[0] != PROXY_PROTOCOL_SEP &&
260
0
            _buf.s[0] != PROXY_PROTOCOL_END[0]) {
261
0
          LM_DBG("bad separator after proxy_protocol UNKNOWN: 0x%x\n",
262
0
              (unsigned char)_buf.s[0]);
263
0
          goto error;
264
0
        }
265
0
        if (_buf.len > PROXY_PROTOCOL_UNKN_PAYLOAD_MAX)
266
0
          _buf.len = PROXY_PROTOCOL_UNKN_PAYLOAD_MAX;
267
0
        af = AF_UNSPEC;
268
0
        max = PROXY_PROTOCOL_UNKN_MAX;
269
0
      } else if (m == PP_TOK_PARTIAL) {
270
0
        return NULL;
271
0
      } else {
272
0
        LM_DBG("unknown proxy_protocol proto [%.*s]\n", _buf.len, _buf.s);
273
0
        goto error;
274
0
      }
275
0
    }
276
0
  }
277
278
  /* search for the end within the maximum payload */
279
0
  end = str_strstr(&_buf, _str(PROXY_PROTOCOL_END));
280
0
  if (!end) {
281
0
    if (size < max) /* we still don't have enough data to find the end */
282
0
      return NULL;
283
0
    LM_DBG("could not find proxy_protocol end in [%.*s]\n",
284
0
        _buf.len, _buf.s);
285
0
    goto error;
286
0
  }
287
0
  if (af == AF_UNSPEC) {
288
    /* we have an unknown protocol - stop it here */
289
0
    proxy->flags = PP_UNKNOWN;
290
0
    return end + PROXY_PROTOCOL_END_LEN;
291
0
  }
292
0
  _buf.len = end - _buf.s;
293
  /* src ip */
294
0
  p = q_memchr(_buf.s, PROXY_PROTOCOL_SEP, _buf.len);
295
0
  if (!p)
296
0
    goto error;
297
0
  tmp.s = _buf.s;
298
0
  tmp.len = p - _buf.s;
299
0
  ip = (af == AF_INET?str2ip(&tmp):str2ip6(&tmp));
300
0
  if (!ip) {
301
0
    LM_DBG("could not parse proxy_protocol src ip %.*s for af %d\n",
302
0
        tmp.len, tmp.s, af);
303
0
    goto error;
304
0
  }
305
0
  memcpy(&proxy->src_ip, ip, sizeof *ip);
306
0
  _buf.len -= tmp.len + 1;
307
0
  _buf.s = p + 1;
308
309
  /* dst ip */
310
0
  p = q_memchr(_buf.s, PROXY_PROTOCOL_SEP, _buf.len);
311
0
  if (!p)
312
0
    goto error;
313
0
  tmp.s = _buf.s;
314
0
  tmp.len = p - _buf.s;
315
0
  ip = (af == AF_INET?str2ip(&tmp):str2ip6(&tmp));
316
0
  if (!ip) {
317
0
    LM_DBG("could not parse proxy_protocol dst ip %.*s for af %d\n",
318
0
        tmp.len, tmp.s, af);
319
0
    goto error;
320
0
  }
321
0
  memcpy(&proxy->dst_ip, ip, sizeof *ip);
322
0
  _buf.len -= tmp.len + 1;
323
0
  _buf.s = p + 1;
324
325
  /* src port */
326
0
  p = q_memchr(_buf.s, PROXY_PROTOCOL_SEP, _buf.len);
327
0
  if (!p)
328
0
    goto error;
329
0
  tmp.s = _buf.s;
330
0
  tmp.len = p - _buf.s;
331
0
  if (str2int(&tmp, &port) < 0) {
332
0
    LM_DBG("could not parse proxy_protocol src port %.*s\n", tmp.len, tmp.s);
333
0
    goto error;
334
0
  }
335
0
  if (port > 65535) {
336
0
    LM_DBG("bad proxy_protocol src port %d\n", port);
337
0
    goto error;
338
0
  }
339
0
  proxy->src_port = port;
340
0
  _buf.len -= tmp.len + 1;
341
0
  _buf.s = p + 1;
342
343
  /* dst port */
344
  /* remaining should be just the dst port */
345
0
  if (str2int(&_buf, &port) < 0) {
346
0
    LM_DBG("could not parse proxy_protocol dst port %.*s\n", _buf.len, _buf.s);
347
0
    goto error;
348
0
  }
349
0
  if (port > 65535) {
350
0
    LM_DBG("bad proxy_protocol dst port %d\n", port);
351
0
    goto error;
352
0
  }
353
0
  proxy->dst_port = port;
354
0
  proxy->flags = PP_OK;
355
0
  return end + PROXY_PROTOCOL_END_LEN;
356
0
error:
357
0
  proxy->flags = PP_ERROR;
358
0
  return NULL;
359
0
}
360
361
static int tcp_peek(struct tcp_connection *c, char *buf, int len)
362
0
{
363
0
  int bytes_read;
364
0
  int fd;
365
366
0
  fd=c->fd;
367
0
again:
368
0
  bytes_read=recv(fd, buf, len, MSG_PEEK);
369
370
0
  if(bytes_read==-1){
371
0
    if (errno == EWOULDBLOCK || errno == EAGAIN){
372
0
      return 0; /* nothing has been read */
373
0
    } else if (errno == EINTR) {
374
0
      goto again;
375
0
    } else if (errno == ECONNRESET) {
376
0
      c->state=S_CONN_EOF;
377
0
      LM_DBG("CONN RESET on %p, FD %d\n", c, fd);
378
0
      return -1;
379
0
    } else {
380
0
      LM_ERR("error reading: %s\n",strerror(errno));
381
0
      return -1;
382
0
    }
383
0
  }else if (bytes_read==0){
384
0
    c->state=S_CONN_EOF;
385
0
    LM_DBG("EOF on %p, FD %d\n", c, fd);
386
0
    return -1;
387
0
  }
388
#ifdef EXTRA_DEBUG
389
  LM_DBG("peek %d bytes:\n%.*s\n", bytes_read, bytes_read, buf);
390
#endif
391
0
  return bytes_read;
392
0
}
393
394
static int tcp_drain(struct tcp_connection *c, char *buf, int len)
395
0
{
396
0
  int bytes_read, total = 0;
397
0
  int retries = 0;
398
0
  int fd = c->fd;
399
0
again:
400
0
  bytes_read = read(fd, buf + total, len - total);
401
0
  if (bytes_read < 0) {
402
0
    if (errno == EINTR) {
403
0
      goto again;
404
0
    } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
405
0
      if (++retries > 100) {
406
0
        LM_ERR("failed consuming proxy_protocol header due to repeated EAGAIN\n");
407
0
        return -1;
408
0
      }
409
0
      goto again;
410
0
    } else {
411
0
      LM_ERR("error consuming proxy_protocol header: %s\n", strerror(errno));
412
0
      return -1;
413
0
    }
414
0
  } else if (bytes_read == 0) {
415
0
    c->state = S_CONN_EOF;
416
0
    LM_DBG("EOF on %p, FD %d while consuming proxy_protocol header\n", c, fd);
417
0
    return -1;
418
0
  }
419
0
  total += bytes_read;
420
0
  retries = 0;
421
0
  if (total < len)
422
0
    goto again;
423
424
0
  return total;
425
0
}
426
427
int check_tcp_proxy_protocol(struct tcp_connection *c)
428
0
{
429
0
  static char pp_buf[PROXY_PROTOCOL_BUF_MAX];
430
0
  char *p;
431
0
  int len;
432
433
0
  if (c->flags & F_CONN_DATA_READY)
434
0
    return 1;
435
436
0
  if (!c->rcv.bind_address ||
437
0
      (c->rcv.bind_address->flags & SI_PROXY_IN) == 0) {
438
0
    c->flags |= F_CONN_DATA_READY;
439
0
    return 1;
440
0
  }
441
442
0
  len = tcp_peek(c, pp_buf, PROXY_PROTOCOL_BUF_MAX);
443
0
  if (len < 0)
444
0
    return -1;
445
446
0
  switch (is_net_proxy_protocol(pp_buf, len)) {
447
0
    case -1:
448
0
      return 0;
449
0
    case 0:
450
0
      c->flags |= F_CONN_DATA_READY;
451
0
      return 1;
452
0
    default:
453
      /* parse proxy_protocol fields */
454
0
      break;
455
0
  }
456
457
0
  p = parse_net_proxy_protocol(pp_buf, len, &c->rcv.real_ep);
458
0
  if (!p) {
459
0
    if (c->rcv.real_ep.flags == PP_ERROR) {
460
0
      LM_ERR("could not parse proxy_protocol header\n");
461
0
      return -1;
462
0
    }
463
0
    return 0;
464
0
  }
465
0
  if (c->rcv.real_ep.flags == PP_OK) {
466
0
    LM_DBG("message proxy_protocol %s:%hu -> %s:%hu\n",
467
0
        ip_addr2a(&c->rcv.real_ep.src_ip), c->rcv.real_ep.src_port,
468
0
        ip_addr2a(&c->rcv.real_ep.dst_ip), c->rcv.real_ep.dst_port);
469
0
  } else {
470
0
    LM_DBG("message proxy_protocol UNKNOWN\n");
471
0
  }
472
473
0
  if (tcp_drain(c, pp_buf, p - pp_buf) < 0) {
474
0
    LM_ERR("could not consume PROXY header\n");
475
0
    return -1;
476
0
  }
477
478
0
  c->flags |= F_CONN_DATA_READY;
479
0
  return 1;
480
0
}
481
482
int check_udp_proxy_protocol(char **buf, int *size, struct receive_info *ri)
483
0
{
484
0
  char *p, *msg;
485
0
  int len;
486
487
0
  if (!buf || !*buf || !size || !ri)
488
0
    return -1;
489
490
0
  ri->real_ep.flags = PP_INIT;
491
492
0
  if (!ri->bind_address || (ri->bind_address->flags & SI_PROXY_IN) == 0)
493
0
    return 1;
494
495
0
  msg = *buf;
496
0
  len = *size;
497
498
0
  switch (is_net_proxy_protocol(msg, len)) {
499
0
  case -1:
500
0
  case 0:
501
0
    return 1;
502
0
  default:
503
0
    break;
504
0
  }
505
506
0
  p = parse_net_proxy_protocol(msg, len, &ri->real_ep);
507
0
  if (!p) {
508
0
    if (ri->real_ep.flags == PP_ERROR) {
509
0
      LM_ERR("could not parse proxy_protocol header\n");
510
0
    } else {
511
0
      LM_ERR("incomplete proxy_protocol header in UDP packet\n");
512
0
    }
513
0
    return -1;
514
0
  }
515
516
0
  if (ri->real_ep.flags == PP_OK) {
517
0
    LM_DBG("message proxy_protocol %s:%hu -> %s:%hu\n",
518
0
        ip_addr2a(&ri->real_ep.src_ip), ri->real_ep.src_port,
519
0
        ip_addr2a(&ri->real_ep.dst_ip), ri->real_ep.dst_port);
520
0
  } else {
521
0
    LM_DBG("message proxy_protocol UNKNOWN\n");
522
0
  }
523
524
0
  *size -= p - msg;
525
0
  *buf = p;
526
0
  return 1;
527
0
}