Commit | Line | Data |
---|---|---|
a78b44b5 BS |
1 | /** @file |
2 | * @brief GNUDIP Service class implementation. This class represents the GNUDIP service. | |
3 | * | |
4 | * | |
5 | * | |
6 | * @copyright Intra2net AG | |
7 | * @license GPLv2 | |
8 | */ | |
9 | ||
4de6a9b8 BS |
10 | #include "service_gnudip.hpp" |
11 | #include "util.hpp" | |
a78b44b5 BS |
12 | |
13 | #include <time.h> | |
14 | #include <boost/foreach.hpp> | |
15 | #include <boost/regex.hpp> | |
16 | ||
17 | using namespace std; | |
18 | ||
19 | ||
20 | /** | |
21 | * Default Constructor, needed for object serialization. | |
22 | */ | |
23 | ServiceGnudip::ServiceGnudip() | |
24 | { | |
25 | } | |
26 | ||
27 | ||
28 | /** | |
29 | * Constructor. | |
30 | * @param _hostname The hostname to update | |
31 | * @param _login The login name. | |
32 | * @param _password The corresponding password. | |
33 | */ | |
4553e833 | 34 | ServiceGnudip::ServiceGnudip(const string& _protocol, const string& _gnudip_server, const string& _hostname, const string& _login, const string& _password, const Logger::Ptr& _logger, const int _update_interval, const int _max_updates_within_interval, const int _max_equal_updates_in_succession, const int _dns_cache_ttl, const string& _proxy, const int _proxy_port) |
a78b44b5 BS |
35 | : GnudipServer(_gnudip_server) |
36 | { | |
37 | if ( _update_interval == -1 ) // If _update_interval is default po::option_desc (not specified via config) | |
a01ce6d7 | 38 | set_update_interval(15); // use default protocol value |
a78b44b5 BS |
39 | else |
40 | set_update_interval(_update_interval); | |
41 | ||
42 | if ( _max_updates_within_interval == -1 ) | |
a01ce6d7 | 43 | set_max_updates_within_interval(3); |
a78b44b5 BS |
44 | else |
45 | set_max_updates_within_interval(_max_updates_within_interval); | |
46 | ||
4553e833 BS |
47 | if ( _max_equal_updates_in_succession == -1 ) |
48 | set_max_equal_updates_in_succession(2); | |
49 | else | |
50 | set_max_equal_updates_in_succession(_max_equal_updates_in_succession); | |
51 | ||
a78b44b5 BS |
52 | if ( _dns_cache_ttl == -1 ) |
53 | set_dns_cache_ttl(60); | |
54 | else | |
55 | set_dns_cache_ttl(_dns_cache_ttl); | |
56 | ||
57 | set_protocol(_protocol); | |
58 | set_hostname(_hostname); | |
59 | set_login(_login); | |
60 | set_password(_password); | |
61 | set_logger(_logger); | |
62 | ||
63 | // create http helper class | |
ce70569b | 64 | HTTPHelp = HTTPHelper::Ptr(new HTTPHelper(_logger,_proxy,_proxy_port,_login,_password)); |
a78b44b5 | 65 | |
62df5f33 | 66 | BaseUrl = assemble_base_url(_gnudip_server); |
a78b44b5 BS |
67 | } |
68 | ||
69 | ||
70 | /** | |
71 | * Default destructor | |
72 | */ | |
73 | ServiceGnudip::~ServiceGnudip() | |
74 | { | |
75 | } | |
76 | ||
77 | ||
78 | /** | |
79 | * Assemble the dyndns update url from the given fqhn | |
62df5f33 | 80 | * @param gnudip_server The gnudip update server. |
a78b44b5 BS |
81 | * @return The assembled update url without IP. |
82 | */ | |
62df5f33 | 83 | string ServiceGnudip::assemble_base_url(const string& gnudip_server) const |
a78b44b5 BS |
84 | { |
85 | string base_url; | |
86 | ||
87 | base_url = "http://"; | |
88 | base_url.append(gnudip_server); | |
89 | base_url.append("/gnudip/cgi-bin/gdipupdt.cgi"); | |
90 | ||
91 | return base_url; | |
92 | } | |
93 | ||
94 | ||
95 | /** | |
96 | * Parses the data received from the initial request, which should contain salt, time and sign. | |
97 | * @param curl_data The complete received curl data. | |
98 | * @return A map with salt, time and sign or an empty map. | |
99 | */ | |
100 | map<string,string> ServiceGnudip::parse_initial_request(const string& curl_data) const | |
101 | { | |
102 | map<string,string> response; | |
103 | ||
104 | // regex for salt | |
3208f713 | 105 | boost::regex expr_salt("<meta name=\"salt\" content=\"([^\"]*)\""); |
a78b44b5 | 106 | // regex for time |
3208f713 | 107 | boost::regex expr_time("<meta name=\"time\" content=\"([^\"]*)\""); |
a78b44b5 | 108 | // regex for sign |
3208f713 | 109 | boost::regex expr_sign("<meta name=\"sign\" content=\"([^\"]*)\""); |
a78b44b5 BS |
110 | |
111 | boost::smatch matches; | |
112 | ||
113 | // Get the salt out of received http data | |
114 | if ( boost::regex_search(curl_data,matches,expr_salt) ) | |
115 | { | |
557b6f56 | 116 | response.insert(pair<string,string>("salt",matches[1].str())); /*lint !e534 */ |
62df5f33 | 117 | get_logger()->print_regex_match(expr_salt.str(),matches[1].str()); |
a78b44b5 BS |
118 | } |
119 | else | |
120 | { | |
121 | get_logger()->print_no_regex_match(expr_salt.str(),curl_data); | |
122 | response.clear(); | |
123 | return response; | |
124 | } | |
125 | ||
126 | // Get the time out of received http data | |
127 | if ( boost::regex_search(curl_data,matches,expr_time) ) | |
128 | { | |
557b6f56 | 129 | response.insert(pair<string,string>("time",matches[1].str())); /*lint !e534 */ |
62df5f33 | 130 | get_logger()->print_regex_match(expr_salt.str(),matches[1].str()); |
a78b44b5 BS |
131 | } |
132 | else | |
133 | { | |
134 | get_logger()->print_no_regex_match(expr_salt.str(),curl_data); | |
135 | response.clear(); | |
136 | return response; | |
137 | } | |
138 | ||
139 | // Get the sign out of received http data | |
140 | if ( boost::regex_search(curl_data,matches,expr_sign) ) | |
141 | { | |
557b6f56 | 142 | response.insert(pair<string,string>("sign",matches[1].str())); /*lint !e534 */ |
62df5f33 | 143 | get_logger()->print_regex_match(expr_salt.str(),matches[1].str()); |
a78b44b5 BS |
144 | } |
145 | else | |
146 | { | |
147 | get_logger()->print_no_regex_match(expr_salt.str(),curl_data); | |
148 | response.clear(); | |
149 | return response; | |
150 | } | |
151 | ||
152 | return response; | |
153 | } | |
154 | ||
155 | ||
156 | /** | |
3208f713 BS |
157 | * Parses the data received from the update request, which should contain the return code. |
158 | * @param curl_data The complete received curl data. | |
159 | * @return A string containing the return code of the update request. | |
160 | */ | |
161 | string ServiceGnudip::parse_return_code(const string& curl_data) const | |
162 | { | |
163 | string return_code; | |
164 | ||
165 | // regex for return code | |
166 | boost::regex expr_retc("<meta name=\"retc\" content=\"([^\"]*)\""); | |
167 | boost::smatch matches; | |
168 | ||
169 | // Get the return code out of received http data | |
170 | if ( boost::regex_search(curl_data,matches,expr_retc) ) | |
171 | { | |
172 | return_code = matches[1].str(); | |
173 | get_logger()->print_regex_match(expr_retc.str(),matches[1].str()); | |
174 | } | |
175 | else | |
176 | { | |
177 | get_logger()->print_no_regex_match(expr_retc.str(),curl_data); | |
178 | return return_code; | |
179 | } | |
180 | ||
181 | return return_code; | |
182 | } | |
183 | ||
184 | ||
185 | /** | |
a78b44b5 BS |
186 | * Get the assembled update url. |
187 | * @param salt Salt from the initial request | |
188 | * @param time Time from the initial request | |
189 | * @param sign Sign from the initial request | |
190 | * @param secret Computed md5 secret in HEX | |
191 | * @param ip IP to update | |
192 | * @return The assembled update url. | |
193 | */ | |
62df5f33 | 194 | string ServiceGnudip::assemble_update_url(const string& salt, const string& curr_time, const string& sign, const string& secret, const string& ip) const |
a78b44b5 BS |
195 | { |
196 | string url = BaseUrl; | |
197 | ||
198 | url.append("?salt="); | |
199 | url.append(salt); | |
200 | url.append("&time="); | |
62df5f33 | 201 | url.append(curr_time); |
a78b44b5 BS |
202 | url.append("&sign="); |
203 | url.append(sign); | |
204 | url.append("&user="); | |
205 | url.append(get_login()); | |
206 | url.append("&domn="); | |
3208f713 BS |
207 | string fqhn = get_hostname(); |
208 | string domain = fqhn.substr(fqhn.find('.')+1); | |
209 | url.append(domain); | |
a78b44b5 BS |
210 | url.append("&pass="); |
211 | url.append(secret); | |
212 | url.append("&reqc=0&addr="); | |
213 | url.append(ip); | |
214 | ||
215 | return url; | |
216 | } | |
217 | ||
218 | ||
219 | /** | |
220 | * Performs the Service update. | |
221 | * @param ip IP Address to set. | |
222 | * @return 0 if all is fine, -1 otherwise. | |
223 | */ | |
224 | int ServiceGnudip::perform_update(const std::string& ip) | |
225 | { | |
08a5a621 | 226 | if ( HTTPHelp->is_initialized() ) |
a78b44b5 | 227 | { |
31af6a2e BS |
228 | // initial request |
229 | long http_status_code = HTTPHelp->http_get(BaseUrl); | |
a78b44b5 | 230 | |
31af6a2e | 231 | get_logger()->print_http_status_code(BaseUrl,http_status_code); |
a78b44b5 | 232 | |
31af6a2e | 233 | if ( http_status_code == 200 ) |
a78b44b5 | 234 | { |
31af6a2e BS |
235 | // Get the received http data which should contain the salt, time and sign |
236 | string curl_data = HTTPHelp->get_curl_data(); | |
a78b44b5 | 237 | |
31af6a2e BS |
238 | // Parse salt, time and sign out of the received data |
239 | map<string,string> salt_time_sign = parse_initial_request(curl_data); | |
a78b44b5 | 240 | |
31af6a2e BS |
241 | if ( salt_time_sign.empty() ) |
242 | { | |
243 | get_logger()->print_could_not_parse_received_data(curl_data); | |
244 | return -1; | |
245 | } | |
a78b44b5 | 246 | |
31af6a2e | 247 | // at this point we have salt, time and sign parsed successfully |
62df5f33 | 248 | string salt, sign_time, sign; |
a78b44b5 | 249 | |
31af6a2e BS |
250 | map<string,string>::iterator iter = salt_time_sign.find("salt"); |
251 | if ( iter != salt_time_sign.end() ) | |
252 | salt = iter->second; | |
a78b44b5 | 253 | |
31af6a2e BS |
254 | iter = salt_time_sign.find("time"); |
255 | if ( iter != salt_time_sign.end() ) | |
62df5f33 | 256 | sign_time = iter->second; |
a78b44b5 | 257 | |
31af6a2e BS |
258 | iter = salt_time_sign.find("sign"); |
259 | if ( iter != salt_time_sign.end() ) | |
260 | sign = iter->second; | |
a78b44b5 | 261 | |
62df5f33 | 262 | if ( salt.empty() || sign_time.empty() || sign.empty() ) |
31af6a2e | 263 | get_logger()->print_could_not_get_initial_gnudip_data(); |
a78b44b5 | 264 | |
31af6a2e BS |
265 | // compute md5 sum from users password and get the HEX representation |
266 | string pw_md5_hex; | |
267 | try | |
268 | { | |
269 | pw_md5_hex = Util::compute_md5_digest(get_password()); | |
270 | } | |
c730deea | 271 | catch ( exception& e ) |
31af6a2e BS |
272 | { |
273 | get_logger()->print_exception_md5_sum(e.what()); | |
274 | return -1; | |
275 | } | |
c730deea BS |
276 | catch ( ... ) |
277 | { | |
278 | get_logger()->print_exception_md5_sum("Unknown exception"); | |
279 | return -1; | |
280 | } | |
a78b44b5 | 281 | |
31af6a2e BS |
282 | // append "." and salt and compute md5 sum and get the HEX representation |
283 | pw_md5_hex.append("."); | |
284 | pw_md5_hex.append(salt); | |
a78b44b5 | 285 | |
31af6a2e BS |
286 | string secret; |
287 | try | |
a78b44b5 | 288 | { |
31af6a2e | 289 | secret = Util::compute_md5_digest(pw_md5_hex); |
a78b44b5 | 290 | } |
c730deea | 291 | catch ( exception& e ) |
a78b44b5 | 292 | { |
31af6a2e BS |
293 | get_logger()->print_exception_md5_sum(e.what()); |
294 | return -1; | |
295 | } | |
c730deea BS |
296 | catch ( ... ) |
297 | { | |
298 | get_logger()->print_exception_md5_sum("Unknown exception"); | |
299 | return -1; | |
300 | } | |
31af6a2e BS |
301 | |
302 | // Now its time to issue the second http_get operation | |
62df5f33 | 303 | string url = assemble_update_url(salt, sign_time, sign, secret, ip); |
31af6a2e BS |
304 | |
305 | // perform the update operation | |
306 | http_status_code = HTTPHelp->http_get(url); | |
307 | ||
308 | get_logger()->print_http_status_code(url,http_status_code); | |
309 | ||
310 | if ( http_status_code == 200 ) | |
311 | { | |
312 | // parse the update request return code | |
3208f713 BS |
313 | curl_data = HTTPHelp->get_curl_data(); |
314 | string update_return_code = parse_return_code(curl_data); | |
31af6a2e BS |
315 | if ( update_return_code == "0" ) |
316 | { | |
317 | return 0; | |
318 | } | |
319 | else if ( update_return_code == "1" ) | |
320 | { | |
321 | get_logger()->print_service_not_authorized(url,get_login(),get_password()); | |
322 | } | |
323 | else | |
324 | { | |
325 | get_logger()->print_update_failure(url,update_return_code); | |
326 | } | |
a78b44b5 BS |
327 | } |
328 | else | |
329 | { | |
31af6a2e BS |
330 | // second http get operation (update) was not successful |
331 | get_logger()->print_update_failure(url,http_status_code); | |
a78b44b5 BS |
332 | } |
333 | } | |
334 | else | |
335 | { | |
31af6a2e BS |
336 | // first http get operation was not successful |
337 | get_logger()->print_update_failure(BaseUrl,http_status_code); | |
a78b44b5 BS |
338 | } |
339 | } | |
340 | else | |
341 | { | |
e8787e2e | 342 | get_logger()->print_httphelper_not_initialized(); |
e417b034 | 343 | HTTPHelp->re_initialize(); |
a78b44b5 | 344 | } |
a78b44b5 BS |
345 | return -1; |
346 | } |