shodan_rust/
lib.rs

1use reqwest::{Client, Error};
2use serde_json::Value;
3
4const BASE_URL: &str = "https://api.shodan.io";
5
6/// A minimal async Shodan API client using `reqwest` and `tokio`
7#[derive(Debug, Clone)]
8pub struct ShodanClient {
9    api_key: String,
10    client: Client,
11}
12
13impl ShodanClient {
14    /// Create a new ShodanClient with the given API key.
15    pub fn new(api_key: String) -> Self {
16        Self {
17            api_key,
18            client: Client::new(),
19        }
20    }
21
22    /// Internal request handler for GET requests.
23    async fn request(&self, endpoint: &str) -> Result<Value, Error> {
24        let url = format!("{BASE_URL}/{endpoint}?key={}", self.api_key);
25        let response = self.client.get(&url).send().await?;
26        let json = response.json::<Value>().await?;
27        Ok(json)
28    }
29
30    /// Get information about a specific IP address from Shodan.
31    pub async fn host_info(&self, ip_address: &str) -> Result<Value, Error> {
32        let endpoint = format!("shodan/host/{}", ip_address);
33        self.request(&endpoint).await
34    }
35
36    /// Search Shodan using a search query (e.g. "nginx", "port:22 country:US", etc).
37    pub async fn search(&self, query: &str) -> Result<Value, Error> {
38        let endpoint = format!("shodan/host/search?query={}", query);
39        self.request(&endpoint).await
40    }
41
42    /// Get honeyscore of a host (requires Shodan Labs access).
43    pub async fn honeyscore(&self, ip_address: &str) -> Result<Value, Error> {
44        let endpoint = format!("labs/honeyscore/{}", ip_address);
45        self.request(&endpoint).await
46    }
47}
48
49/// Get host info using a one-shot function interface.
50pub async fn get_host_info(api_key: &str, ip_address: &str) -> Result<Value, Error> {
51    ShodanClient::new(api_key.to_string())
52        .host_info(ip_address)
53        .await
54}
55
56/// Perform a Shodan search using a one-shot function interface.
57pub async fn search_shodan(api_key: &str, query: &str) -> Result<Value, Error> {
58    ShodanClient::new(api_key.to_string())
59        .search(query)
60        .await
61}
62
63/// Get the honeyscore of a host using a one-shot function interface.
64pub async fn get_honeyscore(api_key: &str, ip_address: &str) -> Result<Value, Error> {
65    ShodanClient::new(api_key.to_string())
66        .honeyscore(ip_address)
67        .await
68}