晋太元中,武陵人捕鱼为业。缘溪行,忘路之远近。忽逢桃花林,夹岸数百步,中无杂树,芳草鲜美,落英缤纷。渔人甚异之,复前行,欲穷其林。 林尽水源,便得一山,山有小口,仿佛若有光。便舍船,从口入。初极狭,才通人。复行数十步,豁然开朗。土地平旷,屋舍俨然,有良田、美池、桑竹之属。阡陌交通,鸡犬相闻。其中往来种作,男女衣着,悉如外人。黄发垂髫,并怡然自乐。 见渔人,乃大惊,问所从来。具答之。便要还家,设酒杀鸡作食。村中闻有此人,咸来问讯。自云先世避秦时乱,率妻子邑人来此绝境,不复出焉,遂与外人间隔。问今是何世,乃不知有汉,无论魏晋。此人一一为具言所闻,皆叹惋。余人各复延至其家,皆出酒食。停数日,辞去。此中人语云:“不足为外人道也。”(间隔 一作:隔绝) 既出,得其船,便扶向路,处处志之。及郡下,诣太守,说如此。太守即遣人随其往,寻向所志,遂迷,不复得路。 南阳刘子骥,高尚士也,闻之,欣然规往。未果,寻病终。后遂无问津者。
| DIR:/opt/imunify360/venv/lib/python3.11/site-packages/defence360agent/utils/ |
| Current File : //opt/imunify360/venv/lib/python3.11/site-packages/defence360agent/utils/ipecho.py |
"""IPEchoAPI - returns real IP address of the host (behind NAT)"""
import asyncio
import functools
import logging
import time
import urllib
from pathlib import Path
from typing import Optional
from async_lru import alru_cache
from defence360agent.api.server import API, APIError
from defence360agent.utils import atomic_rewrite
from defence360agent.utils.validate import IP, IPVersion
logger = logging.getLogger(__name__)
TIMEOUT_FOR_IPECHO_REQUEST = 5 # in seconds
CACHE_TTL_SECONDS = 3 * 60 * 60
CACHE_FILE_PATH = Path("/var/imunify360") / "ipecho_cache"
class IPEchoAPI(API):
"""Make requests to the API for obtain own IP address"""
URL = "/api/ip"
@classmethod
@alru_cache(maxsize=3)
async def get_ip(cls, ip_version: IPVersion = None) -> Optional[str]:
"""Return cached result for resolved IP from echo ip API"""
return await cls.ip_for_version(ip_version)
@classmethod
@functools.lru_cache(maxsize=1)
def server_ip(cls):
"""Return cached result for resolved IP from echo ip API"""
try:
return cls._get_ip()
except Exception as e:
raise APIError from e
@classmethod
async def ip_for_version(
cls, ip_version: IPVersion = None
) -> Optional[str]:
"""Return resolved IP from echo ip API"""
loop = asyncio.get_event_loop()
try:
ip = await asyncio.wait_for(
loop.run_in_executor(None, cls._get_ip),
timeout=TIMEOUT_FOR_IPECHO_REQUEST,
)
if IP.type_of(ip) != ip_version:
raise ValueError("Wrong ip type")
return ip
except (asyncio.TimeoutError, ValueError) as e:
raise APIError from e
@classmethod
def _load_cache(cls) -> Optional[str]:
try:
if not CACHE_FILE_PATH.exists():
return None
mtime = CACHE_FILE_PATH.stat().st_mtime
cache_age = time.time() - mtime
if cache_age < 0:
return None
if cache_age < CACHE_TTL_SECONDS:
ip = CACHE_FILE_PATH.read_text().strip()
return ip
else:
return None
except Exception as e:
logger.error("IPEchoAPI cache read error: %s", e)
return None
@classmethod
def _save_cache(cls, ip: str) -> None:
try:
atomic_rewrite(
CACHE_FILE_PATH,
ip,
backup=False,
permissions=0o644,
)
except Exception as e:
logger.error("IPEchoAPI cache write error: %s", e)
@classmethod
def _get_ip(cls):
"""Get IP from file-based cache or send request to API and process response."""
cached_ip = cls._load_cache()
if cached_ip is not None:
return cached_ip
request = urllib.request.Request(cls._BASE_URL + cls.URL)
response = cls.request(request)
if response.get("status") != "ok":
# time inside sync executor
raise APIError("Unexpected API error")
ip = response.get("ip")
if ip:
cls._save_cache(ip)
return ip
|