1 #include "../filezilla.h"
2
3 #include "rawtransfer.h"
4 #include "../servercapabilities.h"
5 #include "transfersocket.h"
6 #include "../../include/engine_options.h"
7
8 #include <libfilezilla/iputils.hpp>
9
10 #include <assert.h>
11
Send()12 int CFtpRawTransferOpData::Send()
13 {
14 if (!controlSocket_.m_pTransferSocket) {
15 log(logmsg::debug_info, L"Empty m_pTransferSocket");
16 return FZ_REPLY_INTERNALERROR;
17 }
18
19 std::wstring cmd;
20 bool measureRTT = false;
21 switch (opState)
22 {
23 case rawtransfer_init:
24 if ((pOldData->binary && controlSocket_.m_lastTypeBinary == 1) ||
25 (!pOldData->binary && controlSocket_.m_lastTypeBinary == 0))
26 {
27 opState = rawtransfer_port_pasv;
28 }
29 else {
30 opState = rawtransfer_type;
31 }
32
33 if (controlSocket_.proxy_layer_) {
34 // Only passive supported
35 // Theoretically could use reverse proxy ability in SOCKS5, but
36 // it is too fragile to set up with all those broken routers and
37 // firewalls sabotaging connections. Regular active mode is hard
38 // enough already
39 bPasv = true;
40 bTriedActive = true;
41 }
42 else {
43 switch (currentServer_.GetPasvMode())
44 {
45 case MODE_PASSIVE:
46 bPasv = true;
47 break;
48 case MODE_ACTIVE:
49 bPasv = false;
50 break;
51 default:
52 bPasv = engine_.GetOptions().get_int(OPTION_USEPASV) != 0;
53 break;
54 }
55 }
56
57 return FZ_REPLY_CONTINUE;
58 case rawtransfer_type:
59 controlSocket_.m_lastTypeBinary = -1;
60 if (pOldData->binary) {
61 cmd = L"TYPE I";
62 }
63 else {
64 cmd = L"TYPE A";
65 }
66 measureRTT = true;
67 break;
68 case rawtransfer_port_pasv:
69 if (bPasv) {
70 cmd = GetPassiveCommand();
71 }
72 else {
73 std::string address;
74 int res = controlSocket_.GetExternalIPAddress(address);
75 if (res == FZ_REPLY_WOULDBLOCK) {
76 return res;
77 }
78 else if (res == FZ_REPLY_OK) {
79 std::wstring portArgument = controlSocket_.m_pTransferSocket->SetupActiveTransfer(address);
80 if (!portArgument.empty()) {
81 bTriedActive = true;
82 if (controlSocket_.socket_->address_family() == fz::address_type::ipv6) {
83 cmd = L"EPRT " + portArgument;
84 }
85 else {
86 cmd = L"PORT " + portArgument;
87 }
88 break;
89 }
90 }
91
92 if (!engine_.GetOptions().get_int(OPTION_ALLOW_TRANSFERMODEFALLBACK) || bTriedPasv) {
93 log(logmsg::error, _("Failed to create listening socket for active mode transfer"));
94 return FZ_REPLY_ERROR;
95 }
96 log(logmsg::debug_warning, _("Failed to create listening socket for active mode transfer"));
97 bTriedActive = true;
98 bPasv = true;
99 cmd = GetPassiveCommand();
100 }
101 break;
102 case rawtransfer_rest:
103 cmd = L"REST " + std::to_wstring(pOldData->resumeOffset);
104 if (pOldData->resumeOffset > 0) {
105 controlSocket_.m_sentRestartOffset = true;
106 }
107 measureRTT = true;
108 break;
109 case rawtransfer_transfer:
110 if (bPasv) {
111 if (!controlSocket_.m_pTransferSocket->SetupPassiveTransfer(host_, port_)) {
112 log(logmsg::error, _("Could not establish connection to server"));
113 return FZ_REPLY_ERROR;
114 }
115 }
116
117 cmd = cmd_;
118 pOldData->tranferCommandSent = true;
119
120 engine_.transfer_status_.SetStartTime();
121 controlSocket_.m_pTransferSocket->SetActive();
122 break;
123 case rawtransfer_waitfinish:
124 case rawtransfer_waittransferpre:
125 case rawtransfer_waittransfer:
126 case rawtransfer_waitsocket:
127 break;
128 default:
129 log(logmsg::debug_warning, L"invalid opstate");
130 return FZ_REPLY_INTERNALERROR;
131 }
132 if (!cmd.empty()) {
133 return controlSocket_.SendCommand(cmd, false, measureRTT);
134 }
135
136 return FZ_REPLY_WOULDBLOCK;
137 }
138
ParseResponse()139 int CFtpRawTransferOpData::ParseResponse()
140 {
141 if (opState == rawtransfer_init) {
142 return FZ_REPLY_ERROR;
143 }
144
145 int const code = controlSocket_.GetReplyCode();
146
147 bool error = false;
148 switch (opState)
149 {
150 case rawtransfer_type:
151 if (code != 2 && code != 3) {
152 error = true;
153 }
154 else {
155 opState = rawtransfer_port_pasv;
156 controlSocket_.m_lastTypeBinary = pOldData->binary ? 1 : 0;
157 }
158 break;
159 case rawtransfer_port_pasv:
160 if (code != 2 && code != 3) {
161 if (!engine_.GetOptions().get_int(OPTION_ALLOW_TRANSFERMODEFALLBACK)) {
162 error = true;
163 break;
164 }
165
166 if (bTriedPasv) {
167 if (bTriedActive) {
168 error = true;
169 }
170 else {
171 bPasv = false;
172 }
173 }
174 else {
175 bPasv = true;
176 }
177 break;
178 }
179 if (bPasv) {
180 bool parsed;
181 if (GetPassiveCommand() == L"EPSV") {
182 parsed = ParseEpsvResponse();
183 }
184 else {
185 parsed = ParsePasvResponse();
186 }
187 if (!parsed) {
188 if (!engine_.GetOptions().get_int(OPTION_ALLOW_TRANSFERMODEFALLBACK)) {
189 error = true;
190 break;
191 }
192
193 if (!bTriedActive) {
194 bPasv = false;
195 }
196 else {
197 error = true;
198 }
199 break;
200 }
201 }
202 if (pOldData->resumeOffset > 0 || controlSocket_.m_sentRestartOffset) {
203 opState = rawtransfer_rest;
204 }
205 else {
206 opState = rawtransfer_transfer;
207 }
208 break;
209 case rawtransfer_rest:
210 if (pOldData->resumeOffset <= 0) {
211 controlSocket_.m_sentRestartOffset = false;
212 }
213 if (pOldData->resumeOffset > 0 && code != 2 && code != 3) {
214 error = true;
215 }
216 else {
217 opState = rawtransfer_transfer;
218 }
219 break;
220 case rawtransfer_transfer:
221 if (code == 1) {
222 opState = rawtransfer_waitfinish;
223 }
224 else if (code == 2 || code == 3) {
225 // A few broken servers omit the 1yz reply.
226 opState = rawtransfer_waitsocket;
227 }
228 else {
229 if (pOldData->transferEndReason == TransferEndReason::successful) {
230 pOldData->transferEndReason = TransferEndReason::transfer_command_failure_immediate;
231 }
232 error = true;
233 }
234 break;
235 case rawtransfer_waittransferpre:
236 if (code == 1) {
237 opState = rawtransfer_waittransfer;
238 }
239 else if (code == 2 || code == 3) {
240 // A few broken servers omit the 1yz reply.
241 if (pOldData->transferEndReason != TransferEndReason::successful) {
242 error = true;
243 break;
244 }
245
246 return FZ_REPLY_OK;
247 }
248 else {
249 if (pOldData->transferEndReason == TransferEndReason::successful) {
250 pOldData->transferEndReason = TransferEndReason::transfer_command_failure_immediate;
251 }
252 error = true;
253 }
254 break;
255 case rawtransfer_waitfinish:
256 if (code != 2 && code != 3) {
257 if (pOldData->transferEndReason == TransferEndReason::successful) {
258 pOldData->transferEndReason = TransferEndReason::transfer_command_failure;
259 }
260 error = true;
261 }
262 else {
263 opState = rawtransfer_waitsocket;
264 }
265 break;
266 case rawtransfer_waittransfer:
267 if (code != 2 && code != 3) {
268 if (pOldData->transferEndReason == TransferEndReason::successful) {
269 pOldData->transferEndReason = TransferEndReason::transfer_command_failure;
270 }
271 error = true;
272 }
273 else {
274 if (pOldData->transferEndReason != TransferEndReason::successful) {
275 error = true;
276 break;
277 }
278
279 return FZ_REPLY_OK;
280 }
281 break;
282 case rawtransfer_waitsocket:
283 log(logmsg::debug_warning, L"Extra reply received during rawtransfer_waitsocket.");
284 error = true;
285 break;
286 default:
287 log(logmsg::debug_warning, L"Unknown op state");
288 error = true;
289 }
290 if (error) {
291 return FZ_REPLY_ERROR;
292 }
293
294 return FZ_REPLY_CONTINUE;
295 }
296
ParseEpsvResponse()297 bool CFtpRawTransferOpData::ParseEpsvResponse()
298 {
299 size_t pos = controlSocket_.m_Response.find(L"(|||");
300 if (pos == std::wstring::npos) {
301 return false;
302 }
303
304 size_t pos2 = controlSocket_.m_Response.find(L"|)", pos + 4);
305 if (pos2 == std::wstring::npos || pos2 == pos + 4) {
306 return false;
307 }
308
309 std::wstring number = controlSocket_.m_Response.substr(pos + 4, pos2 - pos - 4);
310 auto port = fz::to_integral<unsigned int>(number);
311
312 if (port == 0 || port > 65535) {
313 return false;
314 }
315
316 port_ = port;
317
318 if (controlSocket_.proxy_layer_) {
319 host_ = currentServer_.GetHost();
320 }
321 else {
322 host_ = fz::to_wstring(controlSocket_.socket_->peer_ip());
323 }
324 return true;
325 }
326
ParsePasvResponse()327 bool CFtpRawTransferOpData::ParsePasvResponse()
328 {
329 // Validate ip address
330 if (!controlSocket_.m_pasvReplyRegex) {
331 std::wstring digit = L"0*[0-9]{1,3}";
332 wchar_t const* const dot = L",";
333 std::wstring exp = L"( |\\()(" + digit + dot + digit + dot + digit + dot + digit + dot + digit + dot + digit + L")( |\\)|$)";
334 controlSocket_.m_pasvReplyRegex = std::make_unique<std::wregex>(exp);
335 }
336
337 std::wsmatch m;
338 if (!std::regex_search(controlSocket_.m_Response, m, *controlSocket_.m_pasvReplyRegex)) {
339 return false;
340 }
341
342 host_ = m[2].str();
343
344 size_t i = host_.rfind(',');
345 if (i == std::wstring::npos) {
346 return false;
347 }
348 auto number = fz::to_integral<unsigned int>(host_.substr(i + 1));
349 if (number > 255) {
350 return false;
351 }
352
353 port_ = number; //get ls byte of server socket
354 host_ = host_.substr(0, i);
355 i = host_.rfind(',');
356 if (i == std::string::npos) {
357 return false;
358 }
359 number = fz::to_integral<unsigned int>(host_.substr(i + 1));
360 if (number > 255) {
361 return false;
362 }
363
364 port_ += 256 * number; //add ms byte of server socket
365 host_ = host_.substr(0, i);
366 fz::replace_substrings(host_, L",", L".");
367
368 if (controlSocket_.proxy_layer_) {
369 // We do not have any information about the proxy's inner workings
370 return true;
371 }
372
373 std::wstring const peerIP = fz::to_wstring(controlSocket_.socket_->peer_ip());
374 if (!fz::is_routable_address(host_) && fz::is_routable_address(peerIP)) {
375 if (engine_.GetOptions().get_int(OPTION_PASVREPLYFALLBACKMODE) != 1 || bTriedActive) {
376 log(logmsg::status, _("Server sent passive reply with unroutable address. Using server address instead."));
377 log(logmsg::debug_info, L" Reply: %s, peer: %s", host_, peerIP);
378 host_ = peerIP;
379 }
380 else {
381 log(logmsg::status, _("Server sent passive reply with unroutable address. Passive mode failed."));
382 log(logmsg::debug_info, L" Reply: %s, peer: %s", host_, peerIP);
383 return false;
384 }
385 }
386 else if (engine_.GetOptions().get_int(OPTION_PASVREPLYFALLBACKMODE) == 2) {
387 // Always use server address
388 host_ = peerIP;
389 }
390
391 return true;
392 }
393
GetPassiveCommand()394 std::wstring CFtpRawTransferOpData::GetPassiveCommand()
395 {
396 std::wstring ret = L"PASV";
397
398 assert(bPasv);
399 bTriedPasv = true;
400
401 if (controlSocket_.proxy_layer_) {
402 // We don't actually know the address family the other end of the proxy uses to reach the server. Hence prefer EPSV
403 // if the server supports it.
404 if (CServerCapabilities::GetCapability(currentServer_, epsv_command) == yes) {
405 ret = L"EPSV";
406 }
407 }
408 else if (controlSocket_.socket_->address_family() == fz::address_type::ipv6) {
409 // EPSV is mandatory for IPv6, don't check capabilities
410 ret = L"EPSV";
411 }
412 return ret;
413 }
414