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 | ||
10 | #include "service_gnudip.h" | |
11 | #include "util.h" | |
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 | */ | |
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 _dns_cache_ttl, const string& _proxy, const int _proxy_port) | |
35 | : GnudipServer(_gnudip_server) | |
36 | { | |
37 | if ( _update_interval == -1 ) // If _update_interval is default po::option_desc (not specified via config) | |
38 | set_update_interval(0); // use default protocol value | |
39 | else | |
40 | set_update_interval(_update_interval); | |
41 | ||
42 | if ( _max_updates_within_interval == -1 ) | |
43 | set_max_updates_within_interval(0); | |
44 | else | |
45 | set_max_updates_within_interval(_max_updates_within_interval); | |
46 | ||
47 | if ( _dns_cache_ttl == -1 ) | |
48 | set_dns_cache_ttl(60); | |
49 | else | |
50 | set_dns_cache_ttl(_dns_cache_ttl); | |
51 | ||
52 | set_protocol(_protocol); | |
53 | set_hostname(_hostname); | |
54 | set_login(_login); | |
55 | set_password(_password); | |
56 | set_logger(_logger); | |
57 | ||
58 | // create http helper class | |
59 | HTTPHelper::Ptr _http_help(new HTTPHelper(_logger,_proxy,_proxy_port,_login,_password)); | |
a03fb896 | 60 | HTTPHelp.swap(_http_help); |
a78b44b5 BS |
61 | |
62 | BaseUrl = assemble_base_url(get_hostname(),_gnudip_server); | |
63 | } | |
64 | ||
65 | ||
66 | /** | |
67 | * Default destructor | |
68 | */ | |
69 | ServiceGnudip::~ServiceGnudip() | |
70 | { | |
71 | } | |
72 | ||
73 | ||
74 | /** | |
75 | * Assemble the dyndns update url from the given fqhn | |
76 | * @param hostname The fqhn hostname to update IP for. | |
77 | * @return The assembled update url without IP. | |
78 | */ | |
79 | string ServiceGnudip::assemble_base_url(const string& fqhn, const string& gnudip_server) const | |
80 | { | |
81 | string base_url; | |
82 | ||
83 | base_url = "http://"; | |
84 | base_url.append(gnudip_server); | |
85 | base_url.append("/gnudip/cgi-bin/gdipupdt.cgi"); | |
86 | ||
87 | return base_url; | |
88 | } | |
89 | ||
90 | ||
91 | /** | |
92 | * Parses the data received from the initial request, which should contain salt, time and sign. | |
93 | * @param curl_data The complete received curl data. | |
94 | * @return A map with salt, time and sign or an empty map. | |
95 | */ | |
96 | map<string,string> ServiceGnudip::parse_initial_request(const string& curl_data) const | |
97 | { | |
98 | map<string,string> response; | |
99 | ||
100 | // regex for salt | |
101 | boost::regex expr_salt("<meta name=\"salt\" content=\"(.*)\">"); | |
102 | // regex for time | |
103 | boost::regex expr_time("<meta name=\"time\" content=\"(.*)\">"); | |
104 | // regex for sign | |
105 | boost::regex expr_sign("<meta name=\"sign\" content=\"(.*)\">"); | |
106 | ||
107 | boost::smatch matches; | |
108 | ||
109 | // Get the salt out of received http data | |
110 | if ( boost::regex_search(curl_data,matches,expr_salt) ) | |
111 | { | |
112 | response.insert(pair<string,string>("salt",matches[1])); | |
113 | get_logger()->print_regex_match(expr_salt.str(),matches[1]); | |
114 | } | |
115 | else | |
116 | { | |
117 | get_logger()->print_no_regex_match(expr_salt.str(),curl_data); | |
118 | response.clear(); | |
119 | return response; | |
120 | } | |
121 | ||
122 | // Get the time out of received http data | |
123 | if ( boost::regex_search(curl_data,matches,expr_time) ) | |
124 | { | |
125 | response.insert(pair<string,string>("time",matches[1])); | |
126 | get_logger()->print_regex_match(expr_salt.str(),matches[1]); | |
127 | } | |
128 | else | |
129 | { | |
130 | get_logger()->print_no_regex_match(expr_salt.str(),curl_data); | |
131 | response.clear(); | |
132 | return response; | |
133 | } | |
134 | ||
135 | // Get the sign out of received http data | |
136 | if ( boost::regex_search(curl_data,matches,expr_sign) ) | |
137 | { | |
138 | response.insert(pair<string,string>("sign",matches[1])); | |
139 | get_logger()->print_regex_match(expr_salt.str(),matches[1]); | |
140 | } | |
141 | else | |
142 | { | |
143 | get_logger()->print_no_regex_match(expr_salt.str(),curl_data); | |
144 | response.clear(); | |
145 | return response; | |
146 | } | |
147 | ||
148 | return response; | |
149 | } | |
150 | ||
151 | ||
152 | /** | |
153 | * Get the assembled update url. | |
154 | * @param salt Salt from the initial request | |
155 | * @param time Time from the initial request | |
156 | * @param sign Sign from the initial request | |
157 | * @param secret Computed md5 secret in HEX | |
158 | * @param ip IP to update | |
159 | * @return The assembled update url. | |
160 | */ | |
161 | string ServiceGnudip::assemble_update_url(const string& salt, const string& time, const string& sign, const string& secret, const string& ip) const | |
162 | { | |
163 | string url = BaseUrl; | |
164 | ||
165 | url.append("?salt="); | |
166 | url.append(salt); | |
167 | url.append("&time="); | |
168 | url.append(time); | |
169 | url.append("&sign="); | |
170 | url.append(sign); | |
171 | url.append("&user="); | |
172 | url.append(get_login()); | |
173 | url.append("&domn="); | |
174 | url.append(get_hostname()); | |
175 | url.append("&pass="); | |
176 | url.append(secret); | |
177 | url.append("&reqc=0&addr="); | |
178 | url.append(ip); | |
179 | ||
180 | return url; | |
181 | } | |
182 | ||
183 | ||
184 | /** | |
185 | * Performs the Service update. | |
186 | * @param ip IP Address to set. | |
187 | * @return 0 if all is fine, -1 otherwise. | |
188 | */ | |
189 | int ServiceGnudip::perform_update(const std::string& ip) | |
190 | { | |
31af6a2e | 191 | if ( HTTPHelp->is_initialized() == true ) |
a78b44b5 | 192 | { |
31af6a2e BS |
193 | // initial request |
194 | long http_status_code = HTTPHelp->http_get(BaseUrl); | |
a78b44b5 | 195 | |
31af6a2e | 196 | get_logger()->print_http_status_code(BaseUrl,http_status_code); |
a78b44b5 | 197 | |
31af6a2e | 198 | if ( http_status_code == 200 ) |
a78b44b5 | 199 | { |
31af6a2e BS |
200 | // Get the received http data which should contain the salt, time and sign |
201 | string curl_data = HTTPHelp->get_curl_data(); | |
a78b44b5 | 202 | |
31af6a2e BS |
203 | // Parse salt, time and sign out of the received data |
204 | map<string,string> salt_time_sign = parse_initial_request(curl_data); | |
a78b44b5 | 205 | |
31af6a2e BS |
206 | if ( salt_time_sign.empty() ) |
207 | { | |
208 | get_logger()->print_could_not_parse_received_data(curl_data); | |
209 | return -1; | |
210 | } | |
a78b44b5 | 211 | |
31af6a2e BS |
212 | // at this point we have salt, time and sign parsed successfully |
213 | string salt, time, sign; | |
a78b44b5 | 214 | |
31af6a2e BS |
215 | map<string,string>::iterator iter = salt_time_sign.find("salt"); |
216 | if ( iter != salt_time_sign.end() ) | |
217 | salt = iter->second; | |
a78b44b5 | 218 | |
31af6a2e BS |
219 | iter = salt_time_sign.find("time"); |
220 | if ( iter != salt_time_sign.end() ) | |
221 | time = iter->second; | |
a78b44b5 | 222 | |
31af6a2e BS |
223 | iter = salt_time_sign.find("sign"); |
224 | if ( iter != salt_time_sign.end() ) | |
225 | sign = iter->second; | |
a78b44b5 | 226 | |
31af6a2e BS |
227 | if ( salt.empty() || time.empty() || sign.empty() ) |
228 | get_logger()->print_could_not_get_initial_gnudip_data(); | |
a78b44b5 | 229 | |
31af6a2e BS |
230 | // compute md5 sum from users password and get the HEX representation |
231 | string pw_md5_hex; | |
232 | try | |
233 | { | |
234 | pw_md5_hex = Util::compute_md5_digest(get_password()); | |
235 | } | |
236 | catch ( invalid_argument e ) | |
237 | { | |
238 | get_logger()->print_exception_md5_sum(e.what()); | |
239 | return -1; | |
240 | } | |
a78b44b5 | 241 | |
31af6a2e BS |
242 | // append "." and salt and compute md5 sum and get the HEX representation |
243 | pw_md5_hex.append("."); | |
244 | pw_md5_hex.append(salt); | |
a78b44b5 | 245 | |
31af6a2e BS |
246 | string secret; |
247 | try | |
a78b44b5 | 248 | { |
31af6a2e | 249 | secret = Util::compute_md5_digest(pw_md5_hex); |
a78b44b5 | 250 | } |
31af6a2e | 251 | catch ( invalid_argument e ) |
a78b44b5 | 252 | { |
31af6a2e BS |
253 | get_logger()->print_exception_md5_sum(e.what()); |
254 | return -1; | |
255 | } | |
256 | ||
257 | // Now its time to issue the second http_get operation | |
258 | string url = assemble_update_url(salt, time, sign, secret, ip); | |
259 | ||
260 | // perform the update operation | |
261 | http_status_code = HTTPHelp->http_get(url); | |
262 | ||
263 | get_logger()->print_http_status_code(url,http_status_code); | |
264 | ||
265 | if ( http_status_code == 200 ) | |
266 | { | |
267 | // parse the update request return code | |
268 | string update_return_code = HTTPHelp->get_curl_data(); | |
269 | if ( update_return_code == "0" ) | |
270 | { | |
271 | return 0; | |
272 | } | |
273 | else if ( update_return_code == "1" ) | |
274 | { | |
275 | get_logger()->print_service_not_authorized(url,get_login(),get_password()); | |
276 | } | |
277 | else | |
278 | { | |
279 | get_logger()->print_update_failure(url,update_return_code); | |
280 | } | |
a78b44b5 BS |
281 | } |
282 | else | |
283 | { | |
31af6a2e BS |
284 | // second http get operation (update) was not successful |
285 | get_logger()->print_update_failure(url,http_status_code); | |
a78b44b5 BS |
286 | } |
287 | } | |
288 | else | |
289 | { | |
31af6a2e BS |
290 | // first http get operation was not successful |
291 | get_logger()->print_update_failure(BaseUrl,http_status_code); | |
a78b44b5 BS |
292 | } |
293 | } | |
294 | else | |
295 | { | |
31af6a2e | 296 | get_logger()->print_service_not_initialized(BaseUrl); |
a78b44b5 | 297 | } |
a78b44b5 BS |
298 | return -1; |
299 | } |