6 typedef enum socks5_auth_method_t {
10 } socks5_auth_method_t;
12 // SOCKS 4 constants (https://en.wikipedia.org/wiki/SOCKS#SOCKS4)
13 static const uint8_t SOCKS4_CMD_CONN = 1;
14 static const uint8_t SOCKS4_REPLY_VERSION = 0;
15 static const uint8_t SOCKS4_STATUS_OK = 0x5A;
16 static const uint8_t SOCKS4_VERSION = 4;
18 // SOCKS 5 constants (https://en.wikipedia.org/wiki/SOCKS#SOCKS5)
19 typedef enum socks5_addr_type_t {
24 static const uint8_t SOCKS5_AUTH_METHOD_NONE = 0;
25 static const uint8_t SOCKS5_AUTH_METHOD_PASSWORD = 2;
26 static const uint8_t SOCKS5_AUTH_OK = 0;
27 static const uint8_t SOCKS5_AUTH_VERSION = 1;
28 static const uint8_t SOCKS5_COMMAND_CONN = 1;
29 static const uint8_t SOCKS5_STATUS_OK = 0;
30 static const uint8_t SOCKS5_VERSION = 5;
32 static void log_proxy_grant(bool granted) {
34 logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Proxy request granted");
36 logger(DEBUG_CONNECTIONS, LOG_ERR, "Proxy request rejected");
40 static void log_short_response(void) {
41 logger(DEBUG_CONNECTIONS, LOG_ERR, "Received short response from proxy");
44 static bool check_socks4_resp(const socks4_response_t *resp, size_t len) {
45 if(len < sizeof(socks4_response_t)) {
50 if(resp->version != SOCKS4_REPLY_VERSION) {
51 logger(DEBUG_CONNECTIONS, LOG_ERR, "Bad response from SOCKS4 proxy");
55 bool granted = resp->status == SOCKS4_STATUS_OK;
56 log_proxy_grant(granted);
60 static bool socks5_check_result(const socks5_conn_resp_t *re, size_t len) {
63 switch((socks5_addr_type_t)re->addr_type) {
65 addrlen = sizeof(socks5_ipv4_t);
69 addrlen = sizeof(socks5_ipv6_t);
73 logger(DEBUG_CONNECTIONS, LOG_ERR, "Unsupported address type 0x%x from proxy server", re->addr_type);
78 logger(DEBUG_CONNECTIONS, LOG_ERR, "Received short address from proxy server");
82 if(re->socks_version != SOCKS5_VERSION) {
83 logger(DEBUG_CONNECTIONS, LOG_ERR, "Invalid response from proxy server");
87 bool granted = re->conn_status == SOCKS5_STATUS_OK;
88 log_proxy_grant(granted);
92 static bool check_socks5_resp(const socks5_resp_t *resp, size_t len) {
93 if(len < sizeof(socks5_server_choice_t)) {
98 len -= sizeof(socks5_server_choice_t);
100 if(resp->choice.socks_version != SOCKS5_VERSION) {
101 logger(DEBUG_CONNECTIONS, LOG_ERR, "Invalid response from proxy server");
105 switch((socks5_auth_method_t) resp->choice.auth_method) {
107 if(len < sizeof(socks5_conn_resp_t)) {
108 log_short_response();
111 return socks5_check_result(&resp->anon, len - sizeof(socks5_conn_resp_t));
114 case AUTH_PASSWORD: {
115 size_t header_len = sizeof(socks5_auth_status_t) + sizeof(socks5_conn_resp_t);
117 if(len < header_len) {
118 log_short_response();
122 if(resp->pass.status.auth_version != SOCKS5_AUTH_VERSION) {
123 logger(DEBUG_CONNECTIONS, LOG_ERR, "Invalid proxy authentication protocol version");
127 if(resp->pass.status.auth_status != SOCKS5_AUTH_OK) {
128 logger(DEBUG_CONNECTIONS, LOG_ERR, "Proxy authentication failed");
132 return socks5_check_result(&resp->pass.resp, len - header_len);
136 logger(DEBUG_CONNECTIONS, LOG_ERR, "Proxy request rejected: unsuitable authentication method");
140 logger(DEBUG_CONNECTIONS, LOG_ERR, "Unsupported authentication method");
145 bool check_socks_resp(proxytype_t type, const void *buf, size_t len) {
146 if(type == PROXY_SOCKS4) {
147 return check_socks4_resp(buf, len);
148 } else if(type == PROXY_SOCKS5) {
149 return check_socks5_resp(buf, len);
155 static size_t create_socks4_req(socks4_request_t *req, const sockaddr_t *sa) {
156 if(sa->sa.sa_family != AF_INET) {
157 logger(DEBUG_ALWAYS, LOG_ERR, "Cannot connect to an IPv6 host through a SOCKS 4 proxy!");
161 req->version = SOCKS4_VERSION;
162 req->command = SOCKS4_CMD_CONN;
163 req->dstport = sa->in.sin_port;
164 req->dstip = sa->in.sin_addr;
167 strcpy(req->id, proxyuser);
172 return sizeof(socks4_response_t);
175 static size_t create_socks5_req(void *buf, const sockaddr_t *sa) {
176 uint16_t family = sa->sa.sa_family;
178 if(family != AF_INET && family != AF_INET6) {
179 logger(DEBUG_ALWAYS, LOG_ERR, "Address family %x not supported for SOCKS 5 proxies!", family);
183 socks5_greet_t *req = buf;
184 req->version = SOCKS5_VERSION;
185 req->nmethods = 1; // only one auth method is supported
187 size_t resplen = sizeof(socks5_server_choice_t);
188 uint8_t *auth = (uint8_t *)buf + sizeof(socks5_greet_t);
190 if(proxyuser && proxypass) {
191 req->authmethod = SOCKS5_AUTH_METHOD_PASSWORD;
193 // field | VER | IDLEN | ID | PWLEN | PW |
194 // bytes | 1 | 1 | 1-255 | 1 | 1-255 |
196 // Assign the first field (auth protocol version)
197 *auth++ = SOCKS5_AUTH_VERSION;
199 size_t userlen = strlen(proxyuser);
200 size_t passlen = strlen(proxypass);
202 // Assign the username length, and copy the username
204 memcpy(auth, proxyuser, userlen);
207 // Do the same for password
209 memcpy(auth, proxypass, passlen);
212 resplen += sizeof(socks5_auth_status_t);
214 req->authmethod = SOCKS5_AUTH_METHOD_NONE;
217 socks5_conn_req_t *conn = (socks5_conn_req_t *) auth;
218 conn->header.version = SOCKS5_VERSION;
219 conn->header.command = SOCKS5_COMMAND_CONN;
220 conn->header.reserved = 0;
222 resplen += sizeof(socks5_conn_resp_t);
224 if(family == AF_INET) {
225 conn->header.addr_type = SOCKS5_IPV4;
226 conn->dst.ipv4.addr = sa->in.sin_addr;
227 conn->dst.ipv4.port = sa->in.sin_port;
228 resplen += sizeof(socks5_ipv4_t);
230 conn->header.addr_type = SOCKS5_IPV6;
231 conn->dst.ipv6.addr = sa->in6.sin6_addr;
232 conn->dst.ipv6.port = sa->in6.sin6_port;
233 resplen += sizeof(socks5_ipv6_t);
239 size_t socks_req_len(proxytype_t type, const sockaddr_t *sa) {
240 uint16_t family = sa->sa.sa_family;
242 if(type == PROXY_SOCKS4) {
243 if(family != AF_INET) {
244 logger(DEBUG_CONNECTIONS, LOG_ERR, "SOCKS 4 only supports IPv4 addresses");
248 size_t userlen_size = 1;
249 size_t userlen = proxyuser ? strlen(proxyuser) : 0;
250 return sizeof(socks4_request_t) + userlen_size + userlen;
253 if(type == PROXY_SOCKS5) {
254 if(family != AF_INET && family != AF_INET6) {
255 logger(DEBUG_CONNECTIONS, LOG_ERR, "SOCKS 5 only supports IPv4 and IPv6");
259 size_t len = sizeof(socks5_greet_t) +
260 sizeof(socks5_conn_hdr_t) +
262 ? sizeof(socks5_ipv4_t)
263 : sizeof(socks5_ipv6_t));
265 if(proxyuser && proxypass) {
266 // version, userlen, user, passlen, pass
267 len += 1 + 1 + strlen(proxyuser) + 1 + strlen(proxypass);
273 logger(DEBUG_CONNECTIONS, LOG_ERR, "Bad proxy type 0x%x", type);
277 size_t create_socks_req(proxytype_t type, void *buf, const sockaddr_t *sa) {
278 if(type == PROXY_SOCKS4) {
279 return create_socks4_req(buf, sa);
280 } else if(type == PROXY_SOCKS5) {
281 return create_socks5_req(buf, sa);