1 /*
2 * Copyright (c) 2019 Antmicro Ltd
3 *
4 * Copyright (c) 2019 Intel Corporation
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <zephyr/logging/log.h>
10 LOG_MODULE_REGISTER(net_socks, CONFIG_SOCKS_LOG_LEVEL);
11
12 #include <zephyr/kernel.h>
13 #include <zephyr/net/socket.h>
14 #include <zephyr/net/net_pkt.h>
15
16 #include "socks.h"
17 #include "socks_internal.h"
18
socks5_method_rsp_cb(struct net_context * ctx,struct net_pkt * pkt,union net_ip_header * ip_hdr,union net_proto_header * proto_hdr,int status,void * user_data)19 static void socks5_method_rsp_cb(struct net_context *ctx,
20 struct net_pkt *pkt,
21 union net_ip_header *ip_hdr,
22 union net_proto_header *proto_hdr,
23 int status,
24 void *user_data)
25 {
26 struct socks5_method_response *method_rsp =
27 (struct socks5_method_response *)user_data;
28
29 if (!pkt || status) {
30 memset(method_rsp, 0, sizeof(struct socks5_method_response));
31 goto end;
32 }
33
34 if (net_pkt_read(pkt, (uint8_t *)method_rsp,
35 sizeof(struct socks5_method_response))) {
36 memset(method_rsp, 0, sizeof(struct socks5_method_response));
37 }
38
39 end:
40 net_pkt_unref(pkt);
41 }
42
socks5_cmd_rsp_cb(struct net_context * ctx,struct net_pkt * pkt,union net_ip_header * ip_hdr,union net_proto_header * proto_hdr,int status,void * user_data)43 static void socks5_cmd_rsp_cb(struct net_context *ctx,
44 struct net_pkt *pkt,
45 union net_ip_header *ip_hdr,
46 union net_proto_header *proto_hdr,
47 int status,
48 void *user_data)
49 {
50 struct socks5_command_response *cmd_rsp =
51 (struct socks5_command_response *)user_data;
52 int size;
53
54 if (!pkt || status) {
55 memset(cmd_rsp, 0,
56 sizeof(struct socks5_command_request_common));
57 goto end;
58 }
59
60 size = sizeof(struct socks5_command_request_common);
61
62 if (net_pkt_read(pkt, (uint8_t *)cmd_rsp, size)) {
63 memset(cmd_rsp, 0,
64 sizeof(struct socks5_command_request_common));
65 }
66
67 end:
68 net_pkt_unref(pkt);
69 }
70
socks5_tcp_connect(struct net_context * ctx,const struct sockaddr * proxy,socklen_t proxy_len,const struct sockaddr * dest,socklen_t dest_len)71 static int socks5_tcp_connect(struct net_context *ctx,
72 const struct sockaddr *proxy,
73 socklen_t proxy_len,
74 const struct sockaddr *dest,
75 socklen_t dest_len)
76 {
77 struct socks5_method_request method_req;
78 struct socks5_method_response method_rsp;
79 struct socks5_command_request cmd_req;
80 struct socks5_command_response cmd_rsp;
81 int size;
82 int ret;
83
84 /* Negotiate authentication method */
85 method_req.r.ver = SOCKS5_PKT_MAGIC;
86
87 /* We only support NOAUTH at the moment */
88 method_req.r.nmethods = 1U;
89 method_req.methods[0] = SOCKS5_AUTH_METHOD_NOAUTH;
90
91 /* size + 1 because just one method is supported */
92 size = sizeof(struct socks5_method_request_common) + 1;
93
94 ret = net_context_sendto(ctx, (uint8_t *)&method_req, size,
95 proxy, proxy_len, NULL, K_NO_WAIT,
96 ctx->user_data);
97 if (ret < 0) {
98 LOG_ERR("Could not send negotiation packet");
99 return ret;
100 }
101
102 ret = net_context_recv(ctx, socks5_method_rsp_cb,
103 K_MSEC(CONFIG_NET_SOCKETS_CONNECT_TIMEOUT),
104 &method_rsp);
105 if (ret < 0) {
106 LOG_ERR("Could not receive negotiation response");
107 return ret;
108 }
109
110 if (method_rsp.ver != SOCKS5_PKT_MAGIC) {
111 LOG_ERR("Invalid negotiation response magic");
112 return -EINVAL;
113 }
114
115 if (method_rsp.method != SOCKS5_AUTH_METHOD_NOAUTH) {
116 LOG_ERR("Invalid negotiation response");
117 return -ENOTSUP;
118 }
119
120 /* Negotiation complete - now connect to destination */
121 cmd_req.r.ver = SOCKS5_PKT_MAGIC;
122 cmd_req.r.cmd = SOCKS5_CMD_CONNECT;
123 cmd_req.r.rsv = SOCKS5_PKT_RSV;
124
125 if (proxy->sa_family == AF_INET) {
126 const struct sockaddr_in *d4 =
127 (struct sockaddr_in *)dest;
128
129 cmd_req.r.atyp = SOCKS5_ATYP_IPV4;
130
131 memcpy(&cmd_req.ipv4_addr.addr,
132 (uint8_t *)&d4->sin_addr,
133 sizeof(cmd_req.ipv4_addr.addr));
134
135 cmd_req.ipv4_addr.port = d4->sin_port;
136
137 size = sizeof(struct socks5_command_request_common)
138 + sizeof(struct socks5_ipv4_addr);
139 } else if (proxy->sa_family == AF_INET6) {
140 const struct sockaddr_in6 *d6 =
141 (struct sockaddr_in6 *)dest;
142
143 cmd_req.r.atyp = SOCKS5_ATYP_IPV6;
144
145 memcpy(&cmd_req.ipv6_addr.addr,
146 (uint8_t *)&d6->sin6_addr,
147 sizeof(cmd_req.ipv6_addr.addr));
148
149 cmd_req.ipv6_addr.port = d6->sin6_port;
150
151 size = sizeof(struct socks5_command_request_common)
152 + sizeof(struct socks5_ipv6_addr);
153 }
154
155 ret = net_context_sendto(ctx, (uint8_t *)&cmd_req, size,
156 proxy, proxy_len, NULL, K_NO_WAIT,
157 ctx->user_data);
158 if (ret < 0) {
159 LOG_ERR("Could not send CONNECT command");
160 return ret;
161 }
162
163 ret = net_context_recv(ctx, socks5_cmd_rsp_cb,
164 K_MSEC(CONFIG_NET_SOCKETS_CONNECT_TIMEOUT),
165 &cmd_rsp);
166 if (ret < 0) {
167 LOG_ERR("Could not receive CONNECT response");
168 return ret;
169 }
170
171 if (cmd_rsp.r.ver != SOCKS5_PKT_MAGIC) {
172 LOG_ERR("Invalid CONNECT response");
173 return -EINVAL;
174 }
175
176 if (cmd_rsp.r.rep != SOCKS5_CMD_RESP_SUCCESS) {
177 LOG_ERR("Unable to connect to destination");
178 return -EINVAL;
179 }
180
181 /* Verifying the rest is not required */
182
183 LOG_DBG("Connection through SOCKS5 proxy successful");
184
185 return 0;
186 }
187
net_socks5_connect(struct net_context * ctx,const struct sockaddr * addr,socklen_t addrlen)188 int net_socks5_connect(struct net_context *ctx, const struct sockaddr *addr,
189 socklen_t addrlen)
190 {
191 struct sockaddr proxy;
192 socklen_t proxy_len;
193 int type;
194 int ret;
195
196 type = net_context_get_type(ctx);
197 /* TODO: Only TCP and TLS supported, UDP and DTLS yet to support. */
198 if (type != SOCK_STREAM) {
199 return -ENOTSUP;
200 }
201
202 ret = net_context_get_option(ctx, NET_OPT_SOCKS5, &proxy, &proxy_len);
203 if (ret < 0) {
204 return ret;
205 }
206
207 /* Connect to Proxy Server */
208 ret = net_context_connect(ctx, &proxy, proxy_len, NULL,
209 K_MSEC(CONFIG_NET_SOCKETS_CONNECT_TIMEOUT),
210 NULL);
211 if (ret < 0) {
212 return ret;
213 }
214
215 return socks5_tcp_connect(ctx, &proxy, proxy_len, addr, addrlen);
216 }
217