Skip to content

Commit cdc65b1

Browse files
committed
Split the lines
Allow more whitespace Change whitelist format to domain:port Tighten the space/tab regex a bit Clear the whitelist when module closes Use map and set instead of vector Don't need to pass in lua interface Use errcodes instead Fixed lua error usage Move comment Got it compiling Update premake5.lua These aren't external Progress Started whitelist code
1 parent 963d53a commit cdc65b1

File tree

3 files changed

+136
-4
lines changed

3 files changed

+136
-4
lines changed

projects/premake5.lua

+17-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@ newoption({
44
value = "path to garrysmod_common directory"
55
})
66

7+
newoption({
8+
trigger = "whitelist",
9+
description = "Enables wrapping of getaddrinfo and a whitelist file to filter valid addresses and ports",
10+
value = "0 or 1"
11+
})
12+
713
local gmcommon = _OPTIONS.gmcommon or os.getenv("GARRYSMOD_COMMON")
14+
local whitelist = _OPTIONS.whitelist == "1"
815
if gmcommon == nil then
916
error("you didn't provide a path to your garrysmod_common (https://github.com/danielga/garrysmod_common) directory")
1017
end
@@ -16,6 +23,7 @@ local LUASOCKET_FOLDER = "../luasocket/src"
1623
CreateWorkspace({name = "socket.core"})
1724
CreateProject({serverside = true, manual_files = true})
1825
files("../source/socket.cpp")
26+
if whitelist then files("../source/whitelist.cpp") defines({"USE_WHITELIST"}) includedirs(LUASOCKET_FOLDER) end
1927
IncludeLuaShared()
2028
links("socket")
2129

@@ -24,6 +32,7 @@ CreateWorkspace({name = "socket.core"})
2432

2533
CreateProject({serverside = false, manual_files = true})
2634
files("../source/socket.cpp")
35+
if whitelist then files("../source/whitelist.cpp") defines({"USE_WHITELIST"}) includedirs(LUASOCKET_FOLDER) end
2736
IncludeLuaShared()
2837
links("socket")
2938

@@ -52,19 +61,23 @@ CreateWorkspace({name = "socket.core"})
5261
IncludeLuaShared()
5362

5463
filter("system:windows")
55-
defines({
64+
local windowsdefines = {
5665
"LUASOCKET_API=__declspec(dllexport)",
5766
"MIME_API=__declspec(dllexport)"
58-
})
67+
}
68+
if whitelist then windowsdefines[#windowsdefines+1] = "getaddrinfo=__wrap_getaddrinfo" end
69+
defines(windowsdefines)
5970
files(LUASOCKET_FOLDER .. "/wsocket.c")
6071
links("ws2_32")
6172

6273
filter("system:not windows")
63-
defines({
74+
local unixdefines = {
6475
"LUASOCKET_API=''",
6576
"UNIX_API=''",
6677
"MIME_API=''"
67-
})
78+
}
79+
if whitelist then unixdefines[#unixdefines+1] = "getaddrinfo=__wrap_getaddrinfo" end
80+
defines(unixdefines)
6881
files(LUASOCKET_FOLDER .. "/usocket.c")
6982

7083
CreateWorkspace({name = "mime.core"})

source/socket.cpp

+29
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,33 @@
22

33
extern "C" int luaopen_socket_core( lua_State *state );
44

5+
int parseWhitelist();
6+
void clearWhitelist();
7+
enum : int
8+
{
9+
PARSE_SUCCESS = 0,
10+
PARSE_CANT_READ = 1,
11+
PARSE_NO_ENTRIES = 2
12+
};
13+
514
GMOD_MODULE_OPEN( )
615
{
16+
#ifdef USE_WHITELIST
17+
switch (parseWhitelist())
18+
{
19+
case PARSE_SUCCESS:
20+
break;
21+
case PARSE_CANT_READ:
22+
LUA->ThrowError("Failed to read whitelist file!");
23+
break;
24+
case PARSE_NO_ENTRIES:
25+
LUA->ThrowError("Didn't find any valid entries in whitelist file!");
26+
break;
27+
default:
28+
break;
29+
}
30+
#endif
31+
732
if( luaopen_socket_core( LUA->GetState( ) ) == 1 )
833
{
934
LUA->Push( -1 );
@@ -15,6 +40,10 @@ GMOD_MODULE_OPEN( )
1540

1641
GMOD_MODULE_CLOSE( )
1742
{
43+
#ifdef USE_WHITELIST
44+
clearWhitelist();
45+
#endif
46+
1847
LUA->PushNil( );
1948
LUA->SetField( GarrysMod::Lua::INDEX_GLOBAL, "socket" );
2049
return 0;

source/whitelist.cpp

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#undef getaddrinfo
2+
3+
#include "socket.h"
4+
#include <map>
5+
#include <set>
6+
#include <fstream>
7+
#include <sstream>
8+
#include <regex>
9+
10+
//Somewhere glua can't read?
11+
const char* whitelistDir = "../gm_socket_whitelist.txt";
12+
std::map<std::string, std::set<std::string> > whitelist;
13+
14+
enum : int
15+
{
16+
PARSE_SUCCESS = 0,
17+
PARSE_CANT_READ = 1,
18+
PARSE_NO_ENTRIES = 2
19+
};
20+
21+
int parseWhitelist()
22+
{
23+
std::ifstream input(whitelistDir);
24+
if (input)
25+
{
26+
std::stringstream filereader;
27+
filereader << input.rdbuf();
28+
std::string filedata = filereader.str();
29+
std::regex line_parser("(?:(?!\r?\n).)+");
30+
std::regex entry_parser("^[ \\t]*([\\w\\.-]+)\\:(\\d+)[ \\t]*$");
31+
for (std::sregex_iterator line = std::sregex_iterator(filedata.begin(), filedata.end(), line_parser), end = std::sregex_iterator(); line != end; ++line)
32+
{
33+
const std::string& linestr = line->operator[](0);
34+
std::smatch match;
35+
if(std::regex_match(linestr, match, entry_parser))
36+
{
37+
whitelist[match[1].str()].insert(match[2].str());
38+
}
39+
}
40+
if (whitelist.empty())
41+
{
42+
return PARSE_NO_ENTRIES;
43+
}
44+
}
45+
else
46+
{
47+
return PARSE_CANT_READ;
48+
}
49+
return PARSE_SUCCESS;
50+
}
51+
52+
void clearWhitelist()
53+
{
54+
whitelist.clear();
55+
}
56+
57+
bool isSafe(const char* pNodeName, const char* pServiceName)
58+
{
59+
std::map<std::string, std::set<std::string> >::iterator domain = whitelist.find(pNodeName);
60+
return domain != whitelist.end() && domain->second.count(pServiceName)==1;
61+
}
62+
63+
extern "C" {
64+
65+
#ifdef _WIN32
66+
INT WSAAPI __wrap_getaddrinfo(
67+
_In_opt_ PCSTR pNodeName,
68+
_In_opt_ PCSTR pServiceName,
69+
_In_opt_ const ADDRINFOA * pHints,
70+
_Outptr_result_maybenull_ PADDRINFOA * ppResult
71+
)
72+
#else
73+
int __wrap_getaddrinfo (__const char *__restrict pNodeName,
74+
__const char *__restrict pServiceName,
75+
__const struct addrinfo *__restrict pHints,
76+
struct addrinfo **__restrict ppResult)
77+
#endif
78+
{
79+
if(isSafe(pNodeName, pServiceName))
80+
{
81+
return getaddrinfo(pNodeName, pServiceName, pHints, ppResult);
82+
}
83+
else
84+
{
85+
*ppResult = nullptr;
86+
return EAI_FAIL;
87+
}
88+
}
89+
90+
}

0 commit comments

Comments
 (0)