mosquitto/lib/socks_mosq.c

471 lines
13 KiB
C
Raw Normal View History

2014-10-02 08:42:19 +00:00
/*
Copyright (c) 2014-2020 Roger Light <roger@atchoo.org>
2014-10-02 08:42:19 +00:00
All rights reserved. This program and the accompanying materials
2020-11-25 17:34:21 +00:00
are made available under the terms of the Eclipse Public License 2.0
2014-10-02 08:42:19 +00:00
and Eclipse Distribution License v1.0 which accompany this distribution.
The Eclipse Public License is available at
2020-11-25 17:34:21 +00:00
https://www.eclipse.org/legal/epl-2.0/
2014-10-02 08:42:19 +00:00
and the Eclipse Distribution License is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
2020-12-01 18:21:59 +00:00
2014-10-02 08:42:19 +00:00
Contributors:
Roger Light - initial implementation and documentation.
*/
#include "config.h"
2014-10-02 08:42:19 +00:00
#include <errno.h>
#include <string.h>
#include <limits.h>
2018-09-20 09:25:27 +00:00
#ifdef WIN32
# include <ws2tcpip.h>
2021-03-21 09:17:53 +00:00
#elif defined(__QNX__)
# include <sys/socket.h>
# include <arpa/inet.h>
# include <netinet/in.h>
2018-09-20 09:25:27 +00:00
#else
# include <arpa/inet.h>
#endif
#if defined(__FreeBSD__) || defined(__OpenBSD__)
# include <sys/socket.h>
# include <netinet/in.h>
#endif
2014-10-02 08:42:19 +00:00
#include "mosquitto_internal.h"
#include "memory_mosq.h"
#include "net_mosq.h"
2015-04-29 20:23:59 +00:00
#include "packet_mosq.h"
2014-10-02 08:42:19 +00:00
#include "send_mosq.h"
2021-03-21 09:17:53 +00:00
#include "socks_mosq.h"
2019-09-25 11:17:17 +00:00
#include "util_mosq.h"
2014-10-02 08:42:19 +00:00
#define SOCKS_AUTH_NONE 0x00U
#define SOCKS_AUTH_GSS 0x01U
#define SOCKS_AUTH_USERPASS 0x02U
#define SOCKS_AUTH_NO_ACCEPTABLE 0xFFU
2014-10-02 08:42:19 +00:00
#define SOCKS_ATYPE_IP_V4 1U /* four bytes */
#define SOCKS_ATYPE_DOMAINNAME 3U /* one byte length, followed by fqdn no null, 256 max chars */
#define SOCKS_ATYPE_IP_V6 4U /* 16 bytes */
2014-10-02 08:42:19 +00:00
#define SOCKS_REPLY_SUCCEEDED 0x00U
#define SOCKS_REPLY_GENERAL_FAILURE 0x01U
#define SOCKS_REPLY_CONNECTION_NOT_ALLOWED 0x02U
#define SOCKS_REPLY_NETWORK_UNREACHABLE 0x03U
#define SOCKS_REPLY_HOST_UNREACHABLE 0x04U
#define SOCKS_REPLY_CONNECTION_REFUSED 0x05U
#define SOCKS_REPLY_TTL_EXPIRED 0x06U
#define SOCKS_REPLY_COMMAND_NOT_SUPPORTED 0x07U
#define SOCKS_REPLY_ADDRESS_TYPE_NOT_SUPPORTED 0x08U
2014-10-02 08:42:19 +00:00
int mosquitto_socks5_set(struct mosquitto *mosq, const char *host, int port, const char *username, const char *password)
{
#ifdef WITH_SOCKS
if(!mosq) return MOSQ_ERR_INVAL;
if(!host || strlen(host) > 256) return MOSQ_ERR_INVAL;
2020-10-17 00:23:08 +00:00
if(port < 1 || port > UINT16_MAX) return MOSQ_ERR_INVAL;
2014-10-02 08:42:19 +00:00
mosquitto__free(mosq->socks5_host);
mosq->socks5_host = NULL;
2014-10-02 08:42:19 +00:00
mosq->socks5_host = mosquitto__strdup(host);
2014-10-02 08:42:19 +00:00
if(!mosq->socks5_host){
return MOSQ_ERR_NOMEM;
}
2020-10-17 00:23:08 +00:00
mosq->socks5_port = (uint16_t)port;
2014-10-02 08:42:19 +00:00
mosquitto__free(mosq->socks5_username);
mosq->socks5_username = NULL;
mosquitto__free(mosq->socks5_password);
mosq->socks5_password = NULL;
2014-10-02 08:42:19 +00:00
if(username){
2020-10-17 00:23:08 +00:00
if(strlen(username) > UINT8_MAX){
return MOSQ_ERR_INVAL;
}
mosq->socks5_username = mosquitto__strdup(username);
2014-10-02 08:42:19 +00:00
if(!mosq->socks5_username){
return MOSQ_ERR_NOMEM;
}
if(password){
2020-10-17 00:23:08 +00:00
if(strlen(password) > UINT8_MAX){
return MOSQ_ERR_INVAL;
}
mosq->socks5_password = mosquitto__strdup(password);
if(!mosq->socks5_password){
mosquitto__free(mosq->socks5_username);
return MOSQ_ERR_NOMEM;
}
2014-10-02 08:42:19 +00:00
}
}
return MOSQ_ERR_SUCCESS;
#else
2021-08-26 09:54:03 +00:00
UNUSED(mosq);
UNUSED(host);
UNUSED(port);
UNUSED(username);
UNUSED(password);
2014-10-02 08:42:19 +00:00
return MOSQ_ERR_NOT_SUPPORTED;
#endif
}
#ifdef WITH_SOCKS
2015-05-16 14:24:24 +00:00
int socks5__send(struct mosquitto *mosq)
2014-10-02 08:42:19 +00:00
{
struct mosquitto__packet *packet;
2020-10-17 00:23:08 +00:00
size_t slen;
uint8_t ulen, plen;
2014-10-02 08:42:19 +00:00
2018-09-18 13:56:47 +00:00
struct in_addr addr_ipv4;
struct in6_addr addr_ipv6;
int ipv4_pton_result;
int ipv6_pton_result;
2020-12-02 10:19:18 +00:00
enum mosquitto_client_state state;
2018-09-18 13:56:47 +00:00
state = mosquitto__get_state(mosq);
if(state == mosq_cs_socks5_new){
packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet));
2014-10-02 08:42:19 +00:00
if(!packet) return MOSQ_ERR_NOMEM;
if(mosq->socks5_username){
packet->packet_length = 4;
}else{
packet->packet_length = 3;
}
packet->payload = mosquitto__malloc(sizeof(uint8_t)*packet->packet_length);
2014-10-02 08:42:19 +00:00
packet->payload[0] = 0x05;
if(mosq->socks5_username){
packet->payload[1] = 2;
packet->payload[2] = SOCKS_AUTH_NONE;
packet->payload[3] = SOCKS_AUTH_USERPASS;
}else{
packet->payload[1] = 1;
packet->payload[2] = SOCKS_AUTH_NONE;
}
mosquitto__set_state(mosq, mosq_cs_socks5_start);
2014-10-02 08:42:19 +00:00
mosq->in_packet.pos = 0;
mosq->in_packet.packet_length = 2;
mosq->in_packet.to_process = 2;
mosq->in_packet.payload = mosquitto__malloc(sizeof(uint8_t)*2);
2014-10-02 08:42:19 +00:00
if(!mosq->in_packet.payload){
mosquitto__free(packet->payload);
mosquitto__free(packet);
2014-10-02 08:42:19 +00:00
return MOSQ_ERR_NOMEM;
}
2015-05-16 13:16:40 +00:00
return packet__queue(mosq, packet);
}else if(state == mosq_cs_socks5_auth_ok){
packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet));
2014-10-02 08:42:19 +00:00
if(!packet) return MOSQ_ERR_NOMEM;
2018-09-18 13:56:47 +00:00
ipv4_pton_result = inet_pton(AF_INET, mosq->host, &addr_ipv4);
ipv6_pton_result = inet_pton(AF_INET6, mosq->host, &addr_ipv6);
if(ipv4_pton_result == 1){
packet->packet_length = 10;
packet->payload = mosquitto__malloc(sizeof(uint8_t)*packet->packet_length);
2018-09-18 13:56:47 +00:00
if(!packet->payload){
mosquitto__free(packet);
return MOSQ_ERR_NOMEM;
}
packet->payload[3] = SOCKS_ATYPE_IP_V4;
memcpy(&(packet->payload[4]), (const void*)&addr_ipv4, 4);
packet->payload[4+4] = MOSQ_MSB(mosq->port);
packet->payload[4+4+1] = MOSQ_LSB(mosq->port);
2018-09-18 13:56:47 +00:00
}else if(ipv6_pton_result == 1){
packet->packet_length = 22;
packet->payload = mosquitto__malloc(sizeof(uint8_t)*packet->packet_length);
2018-09-18 13:56:47 +00:00
if(!packet->payload){
mosquitto__free(packet);
return MOSQ_ERR_NOMEM;
}
packet->payload[3] = SOCKS_ATYPE_IP_V6;
memcpy(&(packet->payload[4]), (const void*)&addr_ipv6, 16);
packet->payload[4+16] = MOSQ_MSB(mosq->port);
packet->payload[4+16+1] = MOSQ_LSB(mosq->port);
2018-09-18 13:56:47 +00:00
}else{
slen = strlen(mosq->host);
if(slen > UCHAR_MAX){
mosquitto__free(packet);
return MOSQ_ERR_NOMEM;
}
2020-10-17 00:23:08 +00:00
packet->packet_length = 7U + (uint32_t)slen;
packet->payload = mosquitto__malloc(sizeof(uint8_t)*packet->packet_length);
2018-09-18 13:56:47 +00:00
if(!packet->payload){
mosquitto__free(packet);
return MOSQ_ERR_NOMEM;
}
packet->payload[3] = SOCKS_ATYPE_DOMAINNAME;
packet->payload[4] = (uint8_t)slen;
memcpy(&(packet->payload[5]), mosq->host, slen);
packet->payload[5+slen] = MOSQ_MSB(mosq->port);
packet->payload[6+slen] = MOSQ_LSB(mosq->port);
}
2018-09-18 13:56:47 +00:00
packet->payload[0] = 0x05;
packet->payload[1] = 0x01;
packet->payload[2] = 0x00;
2014-10-02 08:42:19 +00:00
mosquitto__set_state(mosq, mosq_cs_socks5_request);
2014-10-02 08:42:19 +00:00
mosq->in_packet.pos = 0;
mosq->in_packet.packet_length = 5;
mosq->in_packet.to_process = 5;
mosq->in_packet.payload = mosquitto__malloc(sizeof(uint8_t)*5);
2014-10-02 08:42:19 +00:00
if(!mosq->in_packet.payload){
mosquitto__free(packet->payload);
mosquitto__free(packet);
2014-10-02 08:42:19 +00:00
return MOSQ_ERR_NOMEM;
}
2015-05-16 13:16:40 +00:00
return packet__queue(mosq, packet);
}else if(state == mosq_cs_socks5_send_userpass){
packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet));
2014-10-02 08:42:19 +00:00
if(!packet) return MOSQ_ERR_NOMEM;
2020-10-17 00:23:08 +00:00
ulen = (uint8_t)strlen(mosq->socks5_username);
plen = (uint8_t)strlen(mosq->socks5_password);
packet->packet_length = 3U + ulen + plen;
packet->payload = mosquitto__malloc(sizeof(uint8_t)*packet->packet_length);
2014-10-02 08:42:19 +00:00
packet->payload[0] = 0x01;
packet->payload[1] = ulen;
memcpy(&(packet->payload[2]), mosq->socks5_username, ulen);
packet->payload[2+ulen] = plen;
memcpy(&(packet->payload[3+ulen]), mosq->socks5_password, plen);
mosquitto__set_state(mosq, mosq_cs_socks5_userpass_reply);
2014-10-02 08:42:19 +00:00
mosq->in_packet.pos = 0;
mosq->in_packet.packet_length = 2;
mosq->in_packet.to_process = 2;
mosq->in_packet.payload = mosquitto__malloc(sizeof(uint8_t)*2);
2014-10-02 08:42:19 +00:00
if(!mosq->in_packet.payload){
mosquitto__free(packet->payload);
mosquitto__free(packet);
2014-10-02 08:42:19 +00:00
return MOSQ_ERR_NOMEM;
}
2015-05-16 13:16:40 +00:00
return packet__queue(mosq, packet);
2014-10-02 08:42:19 +00:00
}
return MOSQ_ERR_SUCCESS;
}
2015-05-16 14:24:24 +00:00
int socks5__read(struct mosquitto *mosq)
2014-10-02 08:42:19 +00:00
{
ssize_t len;
uint8_t *payload;
uint8_t i;
2020-12-02 10:19:18 +00:00
enum mosquitto_client_state state;
2014-10-02 08:42:19 +00:00
state = mosquitto__get_state(mosq);
if(state == mosq_cs_socks5_start){
2014-10-02 08:42:19 +00:00
while(mosq->in_packet.to_process > 0){
2015-05-18 08:29:22 +00:00
len = net__read(mosq, &(mosq->in_packet.payload[mosq->in_packet.pos]), mosq->in_packet.to_process);
2014-10-02 08:42:19 +00:00
if(len > 0){
2020-10-17 00:23:08 +00:00
mosq->in_packet.pos += (uint32_t)len;
mosq->in_packet.to_process -= (uint32_t)len;
2014-10-02 08:42:19 +00:00
}else{
#ifdef WIN32
errno = WSAGetLastError();
#endif
if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){
return MOSQ_ERR_SUCCESS;
}else{
2015-05-16 13:16:40 +00:00
packet__cleanup(&mosq->in_packet);
2014-10-02 08:42:19 +00:00
switch(errno){
case 0:
return MOSQ_ERR_PROXY;
case COMPAT_ECONNRESET:
return MOSQ_ERR_CONN_LOST;
default:
return MOSQ_ERR_ERRNO;
}
}
}
}
if(mosq->in_packet.payload[0] != 5){
2015-05-16 13:16:40 +00:00
packet__cleanup(&mosq->in_packet);
2014-10-02 08:42:19 +00:00
return MOSQ_ERR_PROXY;
}
switch(mosq->in_packet.payload[1]){
case SOCKS_AUTH_NONE:
2015-05-16 13:16:40 +00:00
packet__cleanup(&mosq->in_packet);
mosquitto__set_state(mosq, mosq_cs_socks5_auth_ok);
2015-05-16 14:24:24 +00:00
return socks5__send(mosq);
2014-10-02 08:42:19 +00:00
case SOCKS_AUTH_USERPASS:
2015-05-16 13:16:40 +00:00
packet__cleanup(&mosq->in_packet);
mosquitto__set_state(mosq, mosq_cs_socks5_send_userpass);
2015-05-16 14:24:24 +00:00
return socks5__send(mosq);
2014-10-02 08:42:19 +00:00
default:
2015-05-16 13:16:40 +00:00
packet__cleanup(&mosq->in_packet);
2014-10-02 08:42:19 +00:00
return MOSQ_ERR_AUTH;
}
}else if(state == mosq_cs_socks5_userpass_reply){
2014-10-02 08:42:19 +00:00
while(mosq->in_packet.to_process > 0){
2015-05-18 08:29:22 +00:00
len = net__read(mosq, &(mosq->in_packet.payload[mosq->in_packet.pos]), mosq->in_packet.to_process);
2014-10-02 08:42:19 +00:00
if(len > 0){
2020-10-17 00:23:08 +00:00
mosq->in_packet.pos += (uint32_t)len;
mosq->in_packet.to_process -= (uint32_t)len;
2014-10-02 08:42:19 +00:00
}else{
#ifdef WIN32
errno = WSAGetLastError();
#endif
if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){
return MOSQ_ERR_SUCCESS;
}else{
2015-05-16 13:16:40 +00:00
packet__cleanup(&mosq->in_packet);
2014-10-02 08:42:19 +00:00
switch(errno){
case 0:
return MOSQ_ERR_PROXY;
case COMPAT_ECONNRESET:
return MOSQ_ERR_CONN_LOST;
default:
return MOSQ_ERR_ERRNO;
}
}
}
}
if(mosq->in_packet.payload[0] != 1){
2015-05-16 13:16:40 +00:00
packet__cleanup(&mosq->in_packet);
2014-10-02 08:42:19 +00:00
return MOSQ_ERR_PROXY;
}
if(mosq->in_packet.payload[1] == 0){
2015-05-16 13:16:40 +00:00
packet__cleanup(&mosq->in_packet);
mosquitto__set_state(mosq, mosq_cs_socks5_auth_ok);
2015-05-16 14:24:24 +00:00
return socks5__send(mosq);
2014-10-02 08:42:19 +00:00
}else{
i = mosq->in_packet.payload[1];
2015-05-16 13:16:40 +00:00
packet__cleanup(&mosq->in_packet);
2014-10-02 08:42:19 +00:00
switch(i){
case SOCKS_REPLY_CONNECTION_NOT_ALLOWED:
return MOSQ_ERR_AUTH;
case SOCKS_REPLY_NETWORK_UNREACHABLE:
case SOCKS_REPLY_HOST_UNREACHABLE:
case SOCKS_REPLY_CONNECTION_REFUSED:
return MOSQ_ERR_NO_CONN;
case SOCKS_REPLY_GENERAL_FAILURE:
case SOCKS_REPLY_TTL_EXPIRED:
case SOCKS_REPLY_COMMAND_NOT_SUPPORTED:
case SOCKS_REPLY_ADDRESS_TYPE_NOT_SUPPORTED:
return MOSQ_ERR_PROXY;
default:
return MOSQ_ERR_INVAL;
}
return MOSQ_ERR_PROXY;
}
}else if(state == mosq_cs_socks5_request){
2014-10-02 08:42:19 +00:00
while(mosq->in_packet.to_process > 0){
2015-05-18 08:29:22 +00:00
len = net__read(mosq, &(mosq->in_packet.payload[mosq->in_packet.pos]), mosq->in_packet.to_process);
2014-10-02 08:42:19 +00:00
if(len > 0){
2020-10-17 00:23:08 +00:00
mosq->in_packet.pos += (uint32_t)len;
mosq->in_packet.to_process -= (uint32_t)len;
2014-10-02 08:42:19 +00:00
}else{
#ifdef WIN32
errno = WSAGetLastError();
#endif
if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){
return MOSQ_ERR_SUCCESS;
}else{
2015-05-16 13:16:40 +00:00
packet__cleanup(&mosq->in_packet);
2014-10-02 08:42:19 +00:00
switch(errno){
case 0:
return MOSQ_ERR_PROXY;
case COMPAT_ECONNRESET:
return MOSQ_ERR_CONN_LOST;
default:
return MOSQ_ERR_ERRNO;
}
}
}
}
if(mosq->in_packet.packet_length == 5){
/* First part of the packet has been received, we now know what else to expect. */
if(mosq->in_packet.payload[3] == SOCKS_ATYPE_IP_V4){
mosq->in_packet.to_process += 4+2-1; /* 4 bytes IPv4, 2 bytes port, -1 byte because we've already read the first byte */
mosq->in_packet.packet_length += 4+2-1;
}else if(mosq->in_packet.payload[3] == SOCKS_ATYPE_IP_V6){
mosq->in_packet.to_process += 16+2-1; /* 16 bytes IPv6, 2 bytes port, -1 byte because we've already read the first byte */
mosq->in_packet.packet_length += 16+2-1;
}else if(mosq->in_packet.payload[3] == SOCKS_ATYPE_DOMAINNAME){
if(mosq->in_packet.payload[4] > 0){
mosq->in_packet.to_process += mosq->in_packet.payload[4];
mosq->in_packet.packet_length += mosq->in_packet.payload[4];
}
2014-10-02 08:42:19 +00:00
}else{
2015-05-16 13:16:40 +00:00
packet__cleanup(&mosq->in_packet);
2014-10-02 08:42:19 +00:00
return MOSQ_ERR_PROTOCOL;
}
payload = mosquitto__realloc(mosq->in_packet.payload, mosq->in_packet.packet_length);
2014-10-02 08:42:19 +00:00
if(payload){
mosq->in_packet.payload = payload;
}else{
2015-05-16 13:16:40 +00:00
packet__cleanup(&mosq->in_packet);
2014-10-02 08:42:19 +00:00
return MOSQ_ERR_NOMEM;
}
return MOSQ_ERR_SUCCESS;
}
/* Entire packet is now read. */
if(mosq->in_packet.payload[0] != 5){
2015-05-16 13:16:40 +00:00
packet__cleanup(&mosq->in_packet);
2014-10-02 08:42:19 +00:00
return MOSQ_ERR_PROXY;
}
if(mosq->in_packet.payload[1] == 0){
/* Auth passed */
2015-05-16 13:16:40 +00:00
packet__cleanup(&mosq->in_packet);
mosquitto__set_state(mosq, mosq_cs_new);
if(mosq->socks5_host){
int rc = net__socket_connect_step3(mosq, mosq->host);
if(rc) return rc;
}
return send__connect(mosq, mosq->keepalive, mosq->clean_start, NULL);
2014-10-02 08:42:19 +00:00
}else{
i = mosq->in_packet.payload[1];
2015-05-16 13:16:40 +00:00
packet__cleanup(&mosq->in_packet);
mosquitto__set_state(mosq, mosq_cs_socks5_new);
2014-10-02 08:42:19 +00:00
switch(i){
case SOCKS_REPLY_CONNECTION_NOT_ALLOWED:
return MOSQ_ERR_AUTH;
case SOCKS_REPLY_NETWORK_UNREACHABLE:
case SOCKS_REPLY_HOST_UNREACHABLE:
case SOCKS_REPLY_CONNECTION_REFUSED:
return MOSQ_ERR_NO_CONN;
case SOCKS_REPLY_GENERAL_FAILURE:
case SOCKS_REPLY_TTL_EXPIRED:
case SOCKS_REPLY_COMMAND_NOT_SUPPORTED:
case SOCKS_REPLY_ADDRESS_TYPE_NOT_SUPPORTED:
return MOSQ_ERR_PROXY;
default:
return MOSQ_ERR_INVAL;
}
}
}else{
2015-05-16 13:16:40 +00:00
return packet__read(mosq);
2014-10-02 08:42:19 +00:00
}
return MOSQ_ERR_SUCCESS;
}
#endif