add IP and AS informations
This commit is contained in:
parent
0fcc49cf26
commit
376a34ddd5
|
@ -59,6 +59,19 @@ version = "1.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "asn-db2"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06cdaeaa434cbef439220bb84896ce0fd36b4452f0325f0a8e5cd21a08d98901"
|
||||||
|
dependencies = [
|
||||||
|
"csv",
|
||||||
|
"ipnet",
|
||||||
|
"serde",
|
||||||
|
"thiserror",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-stream"
|
name = "async-stream"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
|
@ -307,6 +320,27 @@ dependencies = [
|
||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "csv"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe"
|
||||||
|
dependencies = [
|
||||||
|
"csv-core",
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "csv-core"
|
||||||
|
version = "0.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deranged"
|
name = "deranged"
|
||||||
version = "0.3.11"
|
version = "0.3.11"
|
||||||
|
@ -408,6 +442,18 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dns-lookup"
|
||||||
|
version = "2.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5766087c2235fec47fafa4cfecc81e494ee679d0fd4a59887ea0919bfb0e4fc"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"socket2",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.11.0"
|
version = "1.11.0"
|
||||||
|
@ -1872,7 +1918,9 @@ dependencies = [
|
||||||
name = "services"
|
name = "services"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"asn-db2",
|
||||||
"diesel",
|
"diesel",
|
||||||
|
"dns-lookup",
|
||||||
"fluent-templates",
|
"fluent-templates",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"rocket",
|
"rocket",
|
||||||
|
|
|
@ -8,6 +8,8 @@ name = "updater"
|
||||||
path = "src/updater.rs"
|
path = "src/updater.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
asn-db2 = { version = "0.2", default-features = false }
|
||||||
|
dns-lookup = { version = "2.0", default-features = false }
|
||||||
rocket = { version = "0.5", default-features = false }
|
rocket = { version = "0.5", default-features = false }
|
||||||
rocket-accept-language = { version = "0.8", default-features = false }
|
rocket-accept-language = { version = "0.8", default-features = false }
|
||||||
serde = { version = "1.0", default-features = false }
|
serde = { version = "1.0", default-features = false }
|
||||||
|
|
|
@ -19,5 +19,12 @@ table-ipv6 = { -ipv6 }
|
||||||
table-ipv4 = { -ipv4 }
|
table-ipv4 = { -ipv4 }
|
||||||
table-ipv6-availability = { -ipv6 } availability
|
table-ipv6-availability = { -ipv6 } availability
|
||||||
table-ipv4-availability = { -ipv4 } availability
|
table-ipv4-availability = { -ipv4 } availability
|
||||||
|
table-asn = IP info
|
||||||
|
|
||||||
|
dl-ipinfo =
|
||||||
|
.subnet = Subnet
|
||||||
|
.asn = <abbr title="Autonomous System Number">ASN</title>
|
||||||
|
.as-owner = <abbr title="Autonomous System">AS</title> owner
|
||||||
|
.country = Country
|
||||||
|
|
||||||
field-url = Service URL
|
field-url = Service URL
|
||||||
|
|
|
@ -17,7 +17,14 @@ table-server = Serveur
|
||||||
table-time = Moment
|
table-time = Moment
|
||||||
table-ipv6 = { -ipv6 }
|
table-ipv6 = { -ipv6 }
|
||||||
table-ipv4 = { -ipv4 }
|
table-ipv4 = { -ipv4 }
|
||||||
table-ipv6-availability = Disponibilité { -ipv6 }
|
table-ipv6-availability = Dispo { -ipv6 }
|
||||||
table-ipv4-availability = Disponibilité { -ipv4 }
|
table-ipv4-availability = Dispo { -ipv4 }
|
||||||
|
table-asn = Infos IP
|
||||||
|
|
||||||
|
dl-ipinfo =
|
||||||
|
.subnet = Sous-réseau
|
||||||
|
.asn = <abbr title="Autonomous System Number" lang="en">ASN</title>
|
||||||
|
.as-owner = Propriétaire de l'<abbr title="Autonomous System" lang="en">AS</title>
|
||||||
|
.country = Pays
|
||||||
|
|
||||||
field-url = URL du service
|
field-url = URL du service
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE "services" DROP "address_ipv6";
|
||||||
|
ALTER TABLE "services" DROP "address_ipv4";
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE "services" ADD COLUMN "address_ipv6" TEXT NOT NULL DEFAULT "";
|
||||||
|
ALTER TABLE "services" ADD COLUMN "address_ipv4" TEXT NOT NULL DEFAULT "";
|
|
@ -81,6 +81,8 @@ pub async fn check(url: &str, ipv: Option<u8>) -> Result<Services, String> {
|
||||||
ipv4: "".to_string(),
|
ipv4: "".to_string(),
|
||||||
availability_ipv6: "".to_string(),
|
availability_ipv6: "".to_string(),
|
||||||
availability_ipv4: "".to_string(),
|
availability_ipv4: "".to_string(),
|
||||||
|
address_ipv6: "".to_string(),
|
||||||
|
address_ipv4: "".to_string(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Err(e) => Err(e.to_string()),
|
Err(e) => Err(e.to_string()),
|
||||||
|
|
99
src/main.rs
99
src/main.rs
|
@ -7,6 +7,7 @@ use services::{establish_connection, models::*, Software, DATABASE_URL};
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
|
||||||
|
use asn_db2::{Ipv4Database, Ipv6Database};
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use fluent_templates::FluentLoader;
|
use fluent_templates::FluentLoader;
|
||||||
use rocket::{
|
use rocket::{
|
||||||
|
@ -18,7 +19,9 @@ use rocket::{
|
||||||
Request, Response, State,
|
Request, Response, State,
|
||||||
};
|
};
|
||||||
use rocket_accept_language::{language, AcceptLanguage, LanguageIdentifier};
|
use rocket_accept_language::{language, AcceptLanguage, LanguageIdentifier};
|
||||||
|
use serde::Serialize;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
use std::io::BufReader;
|
||||||
use tera::{Context, Tera, Value};
|
use tera::{Context, Tera, Value};
|
||||||
use unic_langid::{langid, subtags::Language};
|
use unic_langid::{langid, subtags::Language};
|
||||||
|
|
||||||
|
@ -67,13 +70,30 @@ fn rocket() -> _ {
|
||||||
let mut tera = Tera::new("templates/*.html.tera").unwrap();
|
let mut tera = Tera::new("templates/*.html.tera").unwrap();
|
||||||
tera.register_function("fluent", FluentLoader::new(&*LOCALES));
|
tera.register_function("fluent", FluentLoader::new(&*LOCALES));
|
||||||
|
|
||||||
|
let db6 = Ipv6Database::from_reader(BufReader::new(
|
||||||
|
File::open("ip2asn-v6.tsv").expect("unable to open ip2asn-v6.tsv"),
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
let db4 = Ipv4Database::from_reader(BufReader::new(
|
||||||
|
File::open("ip2asn-v4.tsv").expect("unable to open ip2asn-v4.tsv"),
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
rocket::build()
|
rocket::build()
|
||||||
.manage(tera)
|
.manage(tera)
|
||||||
|
.manage(db6)
|
||||||
|
.manage(db4)
|
||||||
.attach(Shield::new().enable(Referrer::NoReferrer))
|
.attach(Shield::new().enable(Referrer::NoReferrer))
|
||||||
.attach(HttpHeaders)
|
.attach(HttpHeaders)
|
||||||
.mount(
|
.mount(
|
||||||
"/",
|
"/",
|
||||||
routes![list_services, list_scans, add_service_get, add_service_post, dl],
|
routes![
|
||||||
|
list_services,
|
||||||
|
list_scans,
|
||||||
|
add_service_get,
|
||||||
|
add_service_post,
|
||||||
|
dl
|
||||||
|
],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,9 +102,30 @@ fn dl() -> File {
|
||||||
File::open(DATABASE_URL).unwrap()
|
File::open(DATABASE_URL).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Debug)]
|
||||||
|
struct IpInfo {
|
||||||
|
ip: String,
|
||||||
|
subnet: String,
|
||||||
|
asn: String,
|
||||||
|
country: String,
|
||||||
|
as_owner: String,
|
||||||
|
}
|
||||||
|
#[derive(Serialize, Debug)]
|
||||||
|
struct TemplateServices {
|
||||||
|
url: String,
|
||||||
|
software: String,
|
||||||
|
server: String,
|
||||||
|
ipv6: String,
|
||||||
|
ipv4: String,
|
||||||
|
availability_ipv6: String,
|
||||||
|
availability_ipv4: String,
|
||||||
|
ip_info: Vec<IpInfo>,
|
||||||
|
}
|
||||||
#[get("/?<software>")]
|
#[get("/?<software>")]
|
||||||
fn list_services(
|
fn list_services(
|
||||||
tera: &State<Tera>,
|
tera: &State<Tera>,
|
||||||
|
db6: &State<Ipv6Database>,
|
||||||
|
db4: &State<Ipv4Database>,
|
||||||
al: &AcceptLanguage,
|
al: &AcceptLanguage,
|
||||||
software: Option<Strict<Software>>,
|
software: Option<Strict<Software>>,
|
||||||
) -> RawHtml<String> {
|
) -> RawHtml<String> {
|
||||||
|
@ -93,6 +134,55 @@ fn list_services(
|
||||||
request =
|
request =
|
||||||
request.filter(services::schema::services::software.eq(s.to_string().to_lowercase()));
|
request.filter(services::schema::services::software.eq(s.to_string().to_lowercase()));
|
||||||
}
|
}
|
||||||
|
let services = request
|
||||||
|
.limit(300)
|
||||||
|
.select(Services::as_select())
|
||||||
|
.load(&mut establish_connection())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut templates: Vec<TemplateServices> = vec![];
|
||||||
|
for service in &services {
|
||||||
|
let mut ip_info = vec![];
|
||||||
|
service
|
||||||
|
.address_ipv6
|
||||||
|
.split(',')
|
||||||
|
.filter(|ip| !ip.is_empty())
|
||||||
|
.for_each(|ip| {
|
||||||
|
let info = db6.lookup(ip.parse().unwrap()).unwrap();
|
||||||
|
ip_info.push(IpInfo {
|
||||||
|
ip: ip.to_string(),
|
||||||
|
subnet: info.subnet.to_string(),
|
||||||
|
asn: info.as_number.to_string(),
|
||||||
|
country: info.country.to_string(),
|
||||||
|
as_owner: info.owner.to_string(),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
service
|
||||||
|
.address_ipv4
|
||||||
|
.split(',')
|
||||||
|
.filter(|ip| !ip.is_empty())
|
||||||
|
.for_each(|ip| {
|
||||||
|
let info = db4.lookup(ip.parse().unwrap()).unwrap();
|
||||||
|
ip_info.push(IpInfo {
|
||||||
|
ip: ip.to_string(),
|
||||||
|
subnet: info.subnet.to_string(),
|
||||||
|
asn: info.as_number.to_string(),
|
||||||
|
country: info.country.to_string(),
|
||||||
|
as_owner: info.owner.to_string(),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
templates.push(TemplateServices {
|
||||||
|
url: service.url.to_string(),
|
||||||
|
software: service.software.to_string(),
|
||||||
|
server: service.server.to_string(),
|
||||||
|
ipv6: service.ipv6.to_string(),
|
||||||
|
ipv4: service.ipv4.to_string(),
|
||||||
|
availability_ipv6: service.availability_ipv6.to_string(),
|
||||||
|
availability_ipv4: service.availability_ipv4.to_string(),
|
||||||
|
ip_info,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
RawHtml(
|
RawHtml(
|
||||||
tera.render(
|
tera.render(
|
||||||
|
@ -100,10 +190,7 @@ fn list_services(
|
||||||
&gen_context(
|
&gen_context(
|
||||||
al,
|
al,
|
||||||
json!({
|
json!({
|
||||||
"services": &request.limit(300)
|
"services": &templates,
|
||||||
.select(Services::as_select())
|
|
||||||
.load(&mut establish_connection())
|
|
||||||
.unwrap(),
|
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -193,6 +280,8 @@ async fn add_service_post(
|
||||||
ipv4: "".to_string(),
|
ipv4: "".to_string(),
|
||||||
availability_ipv6: "".to_string(),
|
availability_ipv6: "".to_string(),
|
||||||
availability_ipv4: "".to_string(),
|
availability_ipv4: "".to_string(),
|
||||||
|
address_ipv6: "".to_string(),
|
||||||
|
address_ipv4: "".to_string(),
|
||||||
})
|
})
|
||||||
.execute(&mut establish_connection())
|
.execute(&mut establish_connection())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -12,6 +12,8 @@ pub struct Services {
|
||||||
pub ipv4: String,
|
pub ipv4: String,
|
||||||
pub availability_ipv6: String,
|
pub availability_ipv6: String,
|
||||||
pub availability_ipv4: String,
|
pub availability_ipv4: String,
|
||||||
|
pub address_ipv6: String,
|
||||||
|
pub address_ipv4: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Queryable, Selectable, Insertable, Serialize, Debug)]
|
#[derive(Queryable, Selectable, Insertable, Serialize, Debug)]
|
||||||
|
|
|
@ -19,6 +19,8 @@ diesel::table! {
|
||||||
ipv4 -> Text,
|
ipv4 -> Text,
|
||||||
availability_ipv6 -> Text,
|
availability_ipv6 -> Text,
|
||||||
availability_ipv4 -> Text,
|
availability_ipv4 -> Text,
|
||||||
|
address_ipv6 -> Text,
|
||||||
|
address_ipv4 -> Text,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,8 @@ use diesel::ExpressionMethods;
|
||||||
use diesel::QueryDsl;
|
use diesel::QueryDsl;
|
||||||
use diesel::RunQueryDsl;
|
use diesel::RunQueryDsl;
|
||||||
use diesel::SelectableHelper;
|
use diesel::SelectableHelper;
|
||||||
|
use dns_lookup::lookup_host;
|
||||||
|
use std::net::IpAddr;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
|
@ -65,8 +67,24 @@ async fn main() {
|
||||||
|
|
||||||
let scans_nb = installation_scans.len();
|
let scans_nb = installation_scans.len();
|
||||||
|
|
||||||
|
let ips: Vec<std::net::IpAddr> =
|
||||||
|
match lookup_host(reqwest::Url::parse(&service.url).unwrap().domain().unwrap()) {
|
||||||
|
Ok(i) => i,
|
||||||
|
Err(_) => vec![],
|
||||||
|
};
|
||||||
|
|
||||||
let service_new = check(&service.url, None).await.unwrap_or(service);
|
let service_new = check(&service.url, None).await.unwrap_or(service);
|
||||||
|
|
||||||
|
let mut addr_ipv6 = vec![];
|
||||||
|
let mut addr_ipv4 = vec![];
|
||||||
|
|
||||||
|
for ip in ips {
|
||||||
|
match ip {
|
||||||
|
IpAddr::V6(ip) => addr_ipv6.push(ip.to_string()),
|
||||||
|
IpAddr::V4(ip) => addr_ipv4.push(ip.to_string()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
diesel::update(services.find(&service_new.url))
|
diesel::update(services.find(&service_new.url))
|
||||||
.set((
|
.set((
|
||||||
url.eq(&service_new.url),
|
url.eq(&service_new.url),
|
||||||
|
@ -78,6 +96,8 @@ async fn main() {
|
||||||
.eq(((ipv6_successes as f32 / scans_nb as f32 * 100.0) as u8).to_string()),
|
.eq(((ipv6_successes as f32 / scans_nb as f32 * 100.0) as u8).to_string()),
|
||||||
availability_ipv4
|
availability_ipv4
|
||||||
.eq(((ipv4_successes as f32 / scans_nb as f32 * 100.0) as u8).to_string()),
|
.eq(((ipv4_successes as f32 / scans_nb as f32 * 100.0) as u8).to_string()),
|
||||||
|
address_ipv6.eq(&addr_ipv6.join(",")),
|
||||||
|
address_ipv4.eq(&addr_ipv4.join(",")),
|
||||||
))
|
))
|
||||||
.execute(connection)
|
.execute(connection)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
<th>{{ fluent(key="table-ipv4", lang=ln) }}</th>
|
<th>{{ fluent(key="table-ipv4", lang=ln) }}</th>
|
||||||
<th>{{ fluent(key="table-ipv6-availability", lang=ln) }}</th>
|
<th>{{ fluent(key="table-ipv6-availability", lang=ln) }}</th>
|
||||||
<th>{{ fluent(key="table-ipv4-availability", lang=ln) }}</th>
|
<th>{{ fluent(key="table-ipv4-availability", lang=ln) }}</th>
|
||||||
|
<th>{{ fluent(key="table-asn", lang=ln) }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -28,6 +29,19 @@
|
||||||
<td>{% if service.ipv4 == "ok" %}✓{% else %}—{% endif %}</td>
|
<td>{% if service.ipv4 == "ok" %}✓{% else %}—{% endif %}</td>
|
||||||
<td>{% if service.ipv6 == "" %}—{% else %}{{ service.availability_ipv6 }} %{% endif %}</td>
|
<td>{% if service.ipv6 == "" %}—{% else %}{{ service.availability_ipv6 }} %{% endif %}</td>
|
||||||
<td>{% if service.ipv4 == "" %}—{% else %}{{ service.availability_ipv4 }} %{% endif %}</td>
|
<td>{% if service.ipv4 == "" %}—{% else %}{{ service.availability_ipv4 }} %{% endif %}</td>
|
||||||
|
<td>
|
||||||
|
{% for ip_info in service.ip_info %}
|
||||||
|
<details>
|
||||||
|
<summary>{{ ip_info.ip }}</summary>
|
||||||
|
<dl>
|
||||||
|
<dt>{{ fluent(key="dl-ipinfo.subnet", lang=ln) }}</dt><dd>{{ ip_info.subnet }}<dd>
|
||||||
|
<dt>{{ fluent(key="dl-ipinfo.asn", lang=ln) }}</dt><dd>{{ ip_info.asn }}</dd>
|
||||||
|
<dt>{{ fluent(key="dl-ipinfo.as-owner", lang=ln) }}</dt><dd>{{ ip_info.as_owner }}<dd>
|
||||||
|
<dt>{{ fluent(key="dl-ipinfo.country", lang=ln) }}</dt><dd>{{ ip_info.country }}<dd>
|
||||||
|
</dl>
|
||||||
|
</details>
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
Loading…
Reference in New Issue