1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2 
3 #include "restrictions.h"
4 
5 #include <map>
6 #include <string>
7 
8 #include "System/Log/ILog.h"
9 #include "System/Config/ConfigHandler.h"
10 
11 #define WILDCARD_HOST "*"
12 #define WILDCARD_PORT -1
13 
14 #ifndef TEST
15 #define LOG_SECTION_LUASOCKET "LuaSocket"
16 LOG_REGISTER_SECTION_GLOBAL(LOG_SECTION_LUASOCKET)
17 #ifdef LOG_SECTION_CURRENT
18 	#undef LOG_SECTION_CURRENT
19 #endif
20 #define LOG_SECTION_CURRENT LOG_SECTION_LUASOCKET
21 
22 CONFIG(std::string, TCPAllowConnect).defaultValue(WILDCARD_HOST).readOnly(true);
23 CONFIG(std::string, TCPAllowListen).defaultValue(WILDCARD_HOST).readOnly(true);
24 CONFIG(std::string, UDPAllowConnect).defaultValue("").readOnly(true);
25 CONFIG(std::string, UDPAllowListen).defaultValue(WILDCARD_HOST).readOnly(true);
26 #endif
27 
28 CLuaSocketRestrictions* luaSocketRestrictions=0;
29 
CLuaSocketRestrictions()30 CLuaSocketRestrictions::CLuaSocketRestrictions()
31 {
32 #ifndef TEST
33 	addRules(TCP_CONNECT, configHandler->GetString("TCPAllowConnect"));
34 	addRules(TCP_LISTEN,  configHandler->GetString("TCPAllowListen"));
35 	addRules(UDP_CONNECT, configHandler->GetString("UDPAllowConnect"));
36 	addRules(UDP_LISTEN,  configHandler->GetString("UDPAllowListen"));
37 #endif
38 }
39 
addRule(RestrictType type,const std::string & hostname,int port,bool allowed)40 void CLuaSocketRestrictions::addRule(RestrictType type, const std::string& hostname, int port, bool allowed)
41 {
42 	if ((port !=  WILDCARD_PORT) && ((port<=0) || (port>65535))){
43 		LOG_L(L_ERROR, "Invalid port specified: %d", port);
44 		return;
45 	}
46 	const TSocketRule* rule = getRule(type, hostname.c_str(), port);
47 	if ((rule != NULL) && (rule->allowed == allowed)) {
48 		LOG_L(L_ERROR, "Rule already exists: %s %d", hostname.c_str(), port);
49 		return;
50 	}
51 
52 	if (!allowed) { //add deny rules to the front of the list
53 		restrictions[type].push_front(TSocketRule(hostname, port, allowed));
54 	} else {
55 		restrictions[type].push_back(TSocketRule(hostname, port, allowed));
56 	}
57 }
58 
addRule(RestrictType type,const std::string & rule)59 void CLuaSocketRestrictions::addRule(RestrictType type, const std::string& rule)
60 {
61 	if (rule == WILDCARD_HOST) { //allow everything
62 		restrictions[type].push_back(TSocketRule(WILDCARD_HOST, WILDCARD_PORT, true));
63 		return;
64 	}
65 
66 	size_t delimpos = rule.find(":");
67 	if (delimpos==std::string::npos) {
68 		LOG_L(L_ERROR, "Invalid %d rule: %s, rule has to be hostname:port", type, rule.c_str());
69 		return;
70 	}
71 	const std::string strport = rule.substr(delimpos+1, delimpos-rule.length());
72 	const int port = atoi(strport.c_str());
73 	addRule(type, rule.substr(0, delimpos), port, true);
74 }
75 
addRules(RestrictType type,const std::string & configstr)76 void CLuaSocketRestrictions::addRules(RestrictType type, const std::string& configstr)
77 {
78 	std::string rule;
79 
80 	for(int i=0; i < configstr.length(); i++) {
81 		const char ch = configstr[i];
82 		if ((isspace(ch)) && (!rule.empty())) {
83 			addRule(type, rule);
84 			rule = "";
85 		} else {
86 			rule += ch;
87 		}
88 	}
89 	if (!rule.empty()) {
90 		addRule(type, rule);
91 	}
92 }
93 
94 /*
95 bool isValidIpAddress(char *ipAddress)
96 {
97     struct sockaddr_in sa;
98     int result = inet_pton(AF_INET, ipAddress, &(sa.sin_addr));
99     return result != 0;
100 }
101 */
102 
isAllowed(RestrictType type,const char * hostname,int port)103 bool CLuaSocketRestrictions::isAllowed(RestrictType type, const char* hostname, int port) {
104 	const TSocketRule* rule = getRule(type, hostname, port);
105 	if (rule==NULL) {
106 		return false;
107 	}
108 	return rule->allowed;
109 }
110 
getRule(RestrictType type,const char * hostname,int port)111 const TSocketRule* CLuaSocketRestrictions::getRule(RestrictType type, const char* hostname, int port) {
112 {
113 	int start, end;
114 	if (type != ALL_RULES) {
115 		start = type;
116 		end = start+1;
117 	} else {
118 		start = 0;
119 		end = ALL_RULES;
120 	}
121 	for (int i=start; i<end; i++) {
122 		std::list<TSocketRule>::iterator it;
123 		for(it = restrictions[i].begin(); it != restrictions[i].end(); ++it) {
124 			const TSocketRule& rule = *it;
125 			if ((hostname == rule.hostname) || (rule.hostname == WILDCARD_HOST)) {
126 				if ((rule.port == WILDCARD_PORT) || (rule.port == port)) {
127 					return &rule;
128 				}
129 			}
130 		}
131 	}
132 	return NULL;
133 	}
134 }
135 
addIP(const char * hostname,const char * ip)136 void CLuaSocketRestrictions::addIP(const char* hostname, const char* ip)
137 {
138 	for(int i=0; i<ALL_RULES; i++) {
139 		std::list<TSocketRule>::iterator it;
140 		for(it = restrictions[i].begin(); it != restrictions[i].end(); ++it) {
141 			const TSocketRule &rule = *it;
142 			if ((rule.hostname == hostname)  && (getRule((RestrictType)i, ip, rule.port) == NULL)) { //add rule with ip, when not exisitng
143 				addRule((RestrictType)i, ip, rule.port, rule.allowed);
144 			}
145 		}
146 	}
147 }
148 
ruleToStr(RestrictType type)149 const char* CLuaSocketRestrictions::ruleToStr(RestrictType type) {
150 	switch(type) {
151 		case TCP_CONNECT:
152 			return "TCP_CONNECT";
153 		case TCP_LISTEN:
154 			return "TCP_LISTEN ";
155 		case UDP_LISTEN:
156 			return "UDP_LISTEN ";
157 		case UDP_CONNECT:
158 			return "UDP_CONNECT";
159 		default:
160 			return "INVALID";
161 	}
162 }
163 
~CLuaSocketRestrictions()164 CLuaSocketRestrictions::~CLuaSocketRestrictions()
165 {
166 	LOG("Dumping luasocket rules:");
167 	for(int i=0; i<ALL_RULES; i++) {
168 		std::list<TSocketRule>::iterator it;
169 		for(it = restrictions[i].begin(); it != restrictions[i].end(); ++it) {
170 			TSocketRule &rule = *it;
171 			LOG("%s %s %s %d", ruleToStr((RestrictType)i), rule.allowed ? "ALLOW" : "DENY ", rule.hostname.c_str(), rule.port);
172 		}
173 	}
174 }
175 
176