Coverage Report

Created: 2026-06-07 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mosquitto/src/proxy_v1.c
Line
Count
Source
1
#ifdef WIN32
2
#  include <winsock2.h>
3
#  include <ws2tcpip.h>
4
#else
5
#  include <arpa/inet.h>
6
#endif
7
#include <stdint.h>
8
#include "mosquitto_broker_internal.h"
9
#include "mosquitto_internal.h"
10
#include "net_mosq.h"
11
12
#if !defined(WITH_WEBSOCKETS) || WITH_WEBSOCKETS == WS_IS_BUILTIN
13
14
4.26k
#define PROXY_V1_PACKET_LIMIT 108
15
16
const uint8_t signature4[11] = {'P', 'R', 'O', 'X', 'Y', ' ', 'T', 'C', 'P', '4', ' '};
17
const uint8_t signature6[11] = {'P', 'R', 'O', 'X', 'Y', ' ', 'T', 'C', 'P', '6', ' '};
18
const uint8_t signatureU[14] = {'P', 'R', 'O', 'X', 'Y', ' ', 'U', 'N', 'K', 'N', 'O', 'W', 'N', ' '};
19
20
21
static void proxy_cleanup(struct mosquitto *context)
22
74
{
23
74
  mosquitto_FREE(context->proxy.buf);
24
74
}
25
26
27
static int update_transport(struct mosquitto *context)
28
0
{
29
0
#if defined(WITH_WEBSOCKETS) && WITH_WEBSOCKETS == WS_IS_BUILTIN
30
0
  if(context->listener->protocol == mp_websockets){
31
0
    return http__context_init(context);
32
0
  }else
33
0
#endif
34
0
  {
35
0
    context->transport = mosq_t_tcp;
36
0
  }
37
0
  return MOSQ_ERR_SUCCESS;
38
0
}
39
40
41
static int get_address_for_unknown(struct mosquitto *context)
42
0
{
43
0
  char address[1024];
44
45
0
  proxy_cleanup(context);
46
47
0
  if(!net__socket_get_address(context->sock, address, sizeof(address), &context->remote_port)){
48
0
    context->address = mosquitto_strdup(address);
49
0
  }
50
0
  if(!context->address){
51
0
    return MOSQ_ERR_NOMEM;
52
0
  }
53
0
  return update_transport(context);
54
0
}
55
56
57
static int proxy_v1__decode(struct mosquitto *context)
58
0
{
59
0
  char *saddr_s, *daddr_s, *sport_s, *dport_s;
60
0
  char *saveptr = NULL;
61
0
  int sport, dport;
62
0
  struct in6_addr addr;
63
64
0
  if(context->proxy.pos >= sizeof(signatureU) && !memcmp(context->proxy.buf, signatureU, sizeof(signatureU))){
65
0
    return get_address_for_unknown(context);
66
0
  }else if(context->proxy.pos >= sizeof(signature4) && !memcmp(context->proxy.buf, signature4, sizeof(signature4))){
67
0
    context->proxy.fam = AF_INET;
68
0
  }else if(context->proxy.pos >= sizeof(signature6) && !memcmp(context->proxy.buf, signature6, sizeof(signature6))){
69
0
    context->proxy.fam = AF_INET6;
70
0
  }else{
71
0
    log__printf(NULL, MOSQ_LOG_NOTICE, "Connection rejected, corrupt PROXY header.");
72
0
    proxy_cleanup(context);
73
0
    return MOSQ_ERR_INVAL;
74
0
  }
75
76
0
  context->proxy.buf[context->proxy.pos-1] = '\0';
77
0
  context->proxy.buf[context->proxy.pos-2] = '\0';
78
0
  saddr_s = strtok_r((char *)&context->proxy.buf[sizeof(signature4)], " ", &saveptr);
79
0
  daddr_s = strtok_r(NULL, " ", &saveptr);
80
0
  sport_s = strtok_r(NULL, " ", &saveptr);
81
0
  dport_s = strtok_r(NULL, " ", &saveptr);
82
83
84
0
  if(!saddr_s || !daddr_s || !sport_s || !dport_s || (saveptr && strlen(saveptr) > 0)){
85
0
    log__printf(NULL, MOSQ_LOG_NOTICE, "Connection rejected, corrupt PROXY header.");
86
0
    proxy_cleanup(context);
87
0
    return MOSQ_ERR_INVAL;
88
0
  }
89
90
  /* Verify ports */
91
0
  sport = atoi(sport_s);
92
0
  dport = atoi(dport_s);
93
0
  if(sport < 1 || sport > 65535 || dport < 1 || dport > 65535){
94
0
    log__printf(NULL, MOSQ_LOG_NOTICE, "Connection rejected, corrupt PROXY header.");
95
0
    proxy_cleanup(context);
96
0
    return MOSQ_ERR_INVAL;
97
0
  }
98
99
  /* Verify addresses */
100
0
  if(context->proxy.fam == AF_INET){
101
0
    if(inet_pton(AF_INET, saddr_s, &addr) != 1
102
0
        || inet_pton(AF_INET, daddr_s, &addr) != 1){
103
104
0
      log__printf(NULL, MOSQ_LOG_NOTICE, "Connection rejected, corrupt PROXY header.");
105
0
      proxy_cleanup(context);
106
0
      return MOSQ_ERR_INVAL;
107
0
    }
108
0
  }else if(context->proxy.fam == AF_INET6){
109
0
    if(inet_pton(AF_INET6, saddr_s, &addr) != 1
110
0
        || inet_pton(AF_INET6, daddr_s, &addr) != 1){
111
112
0
      log__printf(NULL, MOSQ_LOG_NOTICE, "Connection rejected, corrupt PROXY header.");
113
0
      proxy_cleanup(context);
114
0
      return MOSQ_ERR_INVAL;
115
0
    }
116
0
  }
117
118
0
  context->address = mosquitto_strdup(saddr_s);
119
0
  if(!context->address){
120
0
    proxy_cleanup(context);
121
0
    return MOSQ_ERR_NOMEM;
122
0
  }
123
0
  context->remote_port = (uint16_t )sport;
124
0
  proxy_cleanup(context);
125
0
  return update_transport(context);
126
0
}
127
128
129
int proxy_v1__read(struct mosquitto *context)
130
74
{
131
74
  if(context->proxy.buf == NULL){
132
74
    context->proxy.buf = mosquitto_calloc(1, PROXY_V1_PACKET_LIMIT);
133
74
    if(!context->proxy.buf){
134
0
      return MOSQ_ERR_NOMEM;
135
0
    }
136
74
    context->proxy.pos = 0;
137
74
  }
138
139
4.16k
  while(context->proxy.pos < PROXY_V1_PACKET_LIMIT){
140
4.12k
    if(net__read(context, &(context->proxy.buf[context->proxy.pos]), 1) != 1){
141
42
      proxy_cleanup(context);
142
42
      return MOSQ_ERR_CONN_LOST;
143
42
    }
144
4.08k
    context->proxy.pos++;
145
4.08k
    if(context->proxy.pos > 2){ /* FIXME: Figure out better limit */
146
3.94k
      if(context->proxy.buf[context->proxy.pos-1] == '\n'
147
417
          && context->proxy.buf[context->proxy.pos-2] == '\r'){
148
149
        /* Line received, now decode */
150
0
        return proxy_v1__decode(context);
151
0
      }
152
3.94k
    }
153
4.08k
  }
154
32
  if(context->proxy.pos == PROXY_V1_PACKET_LIMIT){
155
32
    log__printf(NULL, MOSQ_LOG_NOTICE, "Connection rejected, corrupt PROXY header.");
156
32
    proxy_cleanup(context);
157
32
    return MOSQ_ERR_INVAL;
158
32
  }
159
160
0
  return MOSQ_ERR_SUCCESS;
161
32
}
162
#endif