UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
Socks.inl
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5namespace UE::IoStore::HTTP
6{
7
8#if !UE_BUILD_SHIPPING
9
11static IAS_CVAR(int32, SocksVersion, 5, "SOCKS proxy protocol version to use");
12static IAS_CVAR(FString, SocksIp, "", "Routes all IAS HTTP traffic through the given SOCKS proxy");
13static IAS_CVAR(int32, SocksPort, 1080, "Port of the SOCKS proxy to use");
14
16static uint32 GetSocksIpAddress()
17{
18 const TCHAR* Value = *GSocksIp;
19 uint32 IpAddress = 0;
20 uint32 Accumulator = 0;
21 while (true)
22 {
23 uint32 c = *Value++;
24
25 if (c - '0' <= '9' - '0')
26 {
27 Accumulator *= 10;
28 Accumulator += (c - '0');
29 continue;
30 }
31
32 if (c == '.' || c == '\0')
33 {
34 IpAddress <<= 8;
35 IpAddress |= Accumulator;
36 Accumulator = 0;
37 if (c == '\0')
38 {
39 break;
40 }
41 continue;
42 }
43
44 return 0;
45 }
46 return IpAddress;
47}
48
50static FOutcome ConnectSocks4(FSocket& Socket, uint32 IpAddress, uint32 Port)
51{
52 struct FSocks4Request
53 {
54 uint8 Version = 4;
55 uint8 Command = 1;
56 uint16 Port;
58 };
59
60 struct FSocks4Reply
61 {
63 uint8 Code;
64 uint16 Port;
66 };
67
68 uint32 SocksIpAddress = GetSocksIpAddress();
69 if (!SocksIpAddress)
70 {
71 return FOutcome::Error("Invalid socks IP address");
72 }
73
74 FOutcome Outcome = FOutcome::None();
75
76 if (Outcome = Socket.Connect(SocksIpAddress, GSocksPort); Outcome.IsError())
77 {
78 return Outcome;
79 }
80
82 .Port = Socket_HtoNs(uint16(Port)),
83 .IpAddress = Socket_HtoNl(IpAddress),
84 };
85 if (Outcome = Socket.Send((const char*)&Request, sizeof(Request)); Outcome.IsError())
86 {
87 return Outcome;
88 }
89
90 FSocks4Reply Reply;
91 if (Outcome = Socket.Recv((char*)&Reply, sizeof(Reply)); Outcome.IsError())
92 {
93 return Outcome;
94 }
95
96 return FOutcome::Ok(1);
97}
98
100static FOutcome ConnectSocks5(FSocket& Socket, uint32 IpAddress, uint32 Port)
101{
102#ifdef _MSC_VER
103 // MSVC's static analysis doesn't see that 'Result' from recv() is checked
104 // to be the exact size of the destination buffer.
105#pragma warning(push)
106#pragma warning(disable : 6385)
107#endif
108
109 uint32 SocksIpAddress = GetSocksIpAddress();
110 if (!SocksIpAddress)
111 {
112 return FOutcome::Error("Invalid socks5 IP address");
113 }
114
115 FOutcome Outcome = FOutcome::None();
116
117 if (Outcome = Socket.Connect(SocksIpAddress, GSocksPort); Outcome.IsError())
118 {
119 return Outcome;
120 }
121
122 // Greeting
123 const char Greeting[] = { 5, 1, 0 };
124 Outcome = Socket.Send(Greeting, sizeof(Greeting));
125 if (!Outcome.IsOk()) return Outcome;
126 if (Outcome.GetResult() != sizeof(Greeting))return FOutcome::Error("Could not send socks5 greeting");
127
128 // Server auth-choice
129 char Choice[1 + 1];
130 Outcome = Socket.Recv(Choice, sizeof(Choice));
131 if (!Outcome.IsOk()) return Outcome;
132 if (Outcome.GetResult() != sizeof(Choice)) return FOutcome::Error("Recv too short from socks5 server");
133 if (Choice[0] != 0x05 || Choice[1] != 0x00) return FOutcome::Error("Got unexpected socks5 version from server");
134
135 // Connection request
137 uint16 NsPort = htons(uint16(Port));
138 char Request[] = { 5, 1, 0, 1, 0x11,0x11,0x11,0x11, 0x22,0x22 };
139 std::memcpy(Request + 4, &IpAddress, sizeof(IpAddress));
140 std::memcpy(Request + 8, &NsPort, sizeof(NsPort));
141 Outcome = Socket.Send(Request, sizeof(Request));
142 if (!Outcome.IsOk()) return Outcome;
143 if (Outcome.GetResult() != sizeof(Request)) return FOutcome::Error("Sent too little to socks5 server");
144
145 // Connect reply
146 char Reply[3 + (1 + 4) + 2];
147 Outcome = Socket.Recv(Reply, sizeof(Reply));
148 if (!Outcome.IsOk()) return Outcome;
149 if (Outcome.GetResult() != sizeof(Reply)) return FOutcome::Error("Socks5 reply too short");
150 if (Reply[0] != 0x05 || Reply[1] != 0x00) return FOutcome::Error("Reply has unexpected socks5 version");
151
152 return FOutcome::Ok(1);
153
154#ifdef _MSC_VER
155#pragma warning(pop)
156#endif
157}
158
159#endif // UE_BUILD_SHIPPING
160
162static FOutcome MaybeConnectSocks(FSocket& Socket, uint32 IpAddress, uint32 Port)
163{
164#if UE_BUILD_SHIPPING
165 return FOutcome::Ok();
166#else
167 if (GSocksIp.IsEmpty())
168 {
169 return FOutcome::Ok();
170 }
171
172 Socket.SetBlocking(true);
173
174 switch (GSocksVersion)
175 {
176 case 4: return ConnectSocks4(Socket, IpAddress, Port);
177 case 5: return ConnectSocks5(Socket, IpAddress, Port);
178 }
179
180 return FOutcome::Error("Unsupported socks version");
181#endif // UE_BUILD_SHIPPING
182}
183
184} // namespace UE::IoStore::HTTP
FPlatformTypes::TCHAR TCHAR
Either ANSICHAR or WIDECHAR, depending on whether the platform supports wide characters or the requir...
Definition Platform.h:1135
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
#define IAS_CVAR(Type, Name, Default, Desc,...)
Definition Misc.inl:58
uint8_t uint8
Definition binka_ue_file_header.h:8
uint16_t uint16
Definition binka_ue_file_header.h:7
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition Sockets.h:19
static FOutcome Ok(int32 Result=0)
Definition Misc.inl:113
static FOutcome Error(const char *Message, int32 Code=-1)
Definition Misc.inl:151
static FOutcome None()
Definition Misc.inl:80
@ Socket
Definition EngineTypes.h:3849
const Type Command
Definition GenericApplication.h:46
Definition Client.h:20
uint16 Socket_HtoNs(uint16 v)
Definition Socket.inl:117
uint32 Socket_HtoNl(uint32 v)
Definition Socket.inl:116
Version
Definition NNEModelData.cpp:15