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