Test HTTP/HTTPS connectivity to a specific IP:port
(self, ip, port)
| 336 | return {'error': str(e)[:MAX_ERROR_LENGTH]} |
| 337 | |
| 338 | def test_http_connectivity(self, ip, port): |
| 339 | """Test HTTP/HTTPS connectivity to a specific IP:port""" |
| 340 | results = { |
| 341 | 'http': {'status': False, 'code': None, 'title': None, 'error': None}, |
| 342 | 'https': {'status': False, 'code': None, 'title': None, 'error': None, 'is_self_signed': False} |
| 343 | } |
| 344 | |
| 345 | # Test HTTP |
| 346 | try: |
| 347 | url = f"http://{ip}:{port}" |
| 348 | response = requests.get(url, timeout=self.timeout, allow_redirects=True, verify=False) |
| 349 | results['http']['status'] = True |
| 350 | results['http']['code'] = response.status_code |
| 351 | |
| 352 | # Try to extract title from HTML and save body |
| 353 | if 'text/html' in response.headers.get('content-type', '').lower(): |
| 354 | title_match = re.search(r'<title[^>]*>([^<]+)</title>', response.text, re.IGNORECASE) |
| 355 | if title_match: |
| 356 | results['http']['title'] = title_match.group(1).strip()[:MAX_TITLE_LENGTH] |
| 357 | |
| 358 | # Save response body (safely for JSON) |
| 359 | body_text = response.text[:MAX_BODY_SIZE] if response.text else "" |
| 360 | results['http']['body'] = body_text |
| 361 | |
| 362 | except Exception as e: |
| 363 | results['http']['error'] = str(e)[:MAX_ERROR_LENGTH] |
| 364 | |
| 365 | # Test HTTPS |
| 366 | try: |
| 367 | url = f"https://{ip}:{port}" |
| 368 | |
| 369 | # First try with verification to check if certificate is valid |
| 370 | try: |
| 371 | response = requests.get(url, timeout=self.timeout, allow_redirects=True, verify=True) |
| 372 | results['https']['is_self_signed'] = False # Valid certificate |
| 373 | except requests.exceptions.SSLError: |
| 374 | # SSL error - likely self-signed or invalid certificate |
| 375 | response = requests.get(url, timeout=self.timeout, allow_redirects=True, verify=False) |
| 376 | results['https']['is_self_signed'] = True # Self-signed or invalid |
| 377 | |
| 378 | results['https']['status'] = True |
| 379 | results['https']['code'] = response.status_code |
| 380 | |
| 381 | # Get SSL certificate information using a separate connection (optimized) |
| 382 | # This is still needed because requests doesn't expose detailed cert info |
| 383 | if self.detailed_ssl: |
| 384 | ssl_cert_info = self.get_ssl_certificate_info(ip, port, detailed=True) |
| 385 | results['https']['ssl_certificate'] = ssl_cert_info |
| 386 | else: |
| 387 | # Minimal SSL info for fast scanning |
| 388 | results['https']['ssl_certificate'] = { |
| 389 | 'cipher_suite': 'Unknown', |
| 390 | 'protocol_version': 'Unknown' |
| 391 | } |
| 392 | |
| 393 | # Try to extract title from HTML and save body |
| 394 | if 'text/html' in response.headers.get('content-type', '').lower(): |
| 395 | title_match = re.search(r'<title[^>]*>([^<]+)</title>', response.text, re.IGNORECASE) |
nothing calls this directly
no test coverage detected