Format
This commit is contained in:
parent
45ac24c589
commit
06b34c0e39
|
@ -2,7 +2,7 @@ use flate2::read::GzDecoder;
|
||||||
use hyper::net::HttpsConnector;
|
use hyper::net::HttpsConnector;
|
||||||
use hyper::{self, Client};
|
use hyper::{self, Client};
|
||||||
use hyper_native_tls::NativeTlsClient;
|
use hyper_native_tls::NativeTlsClient;
|
||||||
use std::cmp::{Eq, PartialOrd, PartialEq, Ord, Ordering};
|
use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
|
||||||
use std::collections::Bound::{Included, Unbounded};
|
use std::collections::Bound::{Included, Unbounded};
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
|
|
54
src/main.rs
54
src/main.rs
|
@ -1,25 +1,25 @@
|
||||||
#![cfg_attr(feature="clippy", feature(plugin))]
|
#![cfg_attr(feature = "clippy", feature(plugin))]
|
||||||
#![cfg_attr(feature="clippy", plugin(clippy))]
|
#![cfg_attr(feature = "clippy", plugin(clippy))]
|
||||||
|
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
extern crate flate2;
|
extern crate flate2;
|
||||||
extern crate iron;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate router;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate horrorshow;
|
extern crate horrorshow;
|
||||||
extern crate hyper;
|
extern crate hyper;
|
||||||
extern crate hyper_native_tls;
|
extern crate hyper_native_tls;
|
||||||
extern crate serde;
|
extern crate iron;
|
||||||
extern crate serde_json;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate router;
|
||||||
|
extern crate serde;
|
||||||
|
extern crate serde_json;
|
||||||
|
|
||||||
mod asns;
|
mod asns;
|
||||||
mod webservice;
|
mod webservice;
|
||||||
|
|
||||||
use asns::*;
|
use asns::*;
|
||||||
use clap::{Arg, App};
|
use clap::{App, Arg};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -48,20 +48,24 @@ fn main() {
|
||||||
.version("0.2.0")
|
.version("0.2.0")
|
||||||
.author("Frank Denis")
|
.author("Frank Denis")
|
||||||
.about("Webservice for https://iptoasn.com")
|
.about("Webservice for https://iptoasn.com")
|
||||||
.arg(Arg::with_name("listen_addr")
|
.arg(
|
||||||
.short("l")
|
Arg::with_name("listen_addr")
|
||||||
.long("listen")
|
.short("l")
|
||||||
.value_name("ip:port")
|
.long("listen")
|
||||||
.help("Webservice IP and port")
|
.value_name("ip:port")
|
||||||
.takes_value(true)
|
.help("Webservice IP and port")
|
||||||
.default_value("0.0.0.0:53661"))
|
.takes_value(true)
|
||||||
.arg(Arg::with_name("db_url")
|
.default_value("0.0.0.0:53661"),
|
||||||
.short("u")
|
)
|
||||||
.long("dburl")
|
.arg(
|
||||||
.value_name("url")
|
Arg::with_name("db_url")
|
||||||
.help("URL of the gzipped database")
|
.short("u")
|
||||||
.takes_value(true)
|
.long("dburl")
|
||||||
.default_value("https://iptoasn.com/data/ip2asn-combined.tsv.gz"))
|
.value_name("url")
|
||||||
|
.help("URL of the gzipped database")
|
||||||
|
.takes_value(true)
|
||||||
|
.default_value("https://iptoasn.com/data/ip2asn-combined.tsv.gz"),
|
||||||
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
let db_url = matches.value_of("db_url").unwrap().to_owned();
|
let db_url = matches.value_of("db_url").unwrap().to_owned();
|
||||||
let listen_addr = matches.value_of("listen_addr").unwrap();
|
let listen_addr = matches.value_of("listen_addr").unwrap();
|
||||||
|
@ -69,9 +73,9 @@ fn main() {
|
||||||
let asns_arc = Arc::new(RwLock::new(Arc::new(asns)));
|
let asns_arc = Arc::new(RwLock::new(Arc::new(asns)));
|
||||||
let asns_arc_copy = asns_arc.clone();
|
let asns_arc_copy = asns_arc.clone();
|
||||||
thread::spawn(move || loop {
|
thread::spawn(move || loop {
|
||||||
thread::sleep(Duration::from_secs(3600));
|
thread::sleep(Duration::from_secs(3600));
|
||||||
update_asns(&asns_arc_copy, &db_url);
|
update_asns(&asns_arc_copy, &db_url);
|
||||||
});
|
});
|
||||||
info!("Starting the webservice");
|
info!("Starting the webservice");
|
||||||
WebService::start(asns_arc, listen_addr);
|
WebService::start(asns_arc, listen_addr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use asns::*;
|
use asns::*;
|
||||||
use horrorshow::prelude::*;
|
use horrorshow::prelude::*;
|
||||||
use iron::{BeforeMiddleware, typemap};
|
use iron::{typemap, BeforeMiddleware};
|
||||||
use iron::headers::{CacheControl, CacheDirective, Accept};
|
use iron::headers::{Accept, CacheControl, CacheDirective};
|
||||||
use iron::mime::*;
|
use iron::mime::*;
|
||||||
use iron::modifiers::Header;
|
use iron::modifiers::Header;
|
||||||
use iron::prelude::*;
|
use iron::prelude::*;
|
||||||
|
@ -45,13 +45,18 @@ pub struct WebService;
|
||||||
|
|
||||||
impl WebService {
|
impl WebService {
|
||||||
fn index(_: &mut Request) -> IronResult<Response> {
|
fn index(_: &mut Request) -> IronResult<Response> {
|
||||||
Ok(Response::with((status::Ok,
|
Ok(Response::with((
|
||||||
Mime(TopLevel::Text,
|
status::Ok,
|
||||||
SubLevel::Plain,
|
Mime(
|
||||||
vec![(Attr::Charset, Value::Utf8)]),
|
TopLevel::Text,
|
||||||
Header(CacheControl(vec![CacheDirective::Public,
|
SubLevel::Plain,
|
||||||
CacheDirective::MaxAge(TTL)])),
|
vec![(Attr::Charset, Value::Utf8)],
|
||||||
"See https://iptoasn.com")))
|
),
|
||||||
|
Header(CacheControl(
|
||||||
|
vec![CacheDirective::Public, CacheDirective::MaxAge(TTL)],
|
||||||
|
)),
|
||||||
|
"See https://iptoasn.com",
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accept_type(req: &Request) -> OutputType {
|
fn accept_type(req: &Request) -> OutputType {
|
||||||
|
@ -74,22 +79,28 @@ impl WebService {
|
||||||
output_type
|
output_type
|
||||||
}
|
}
|
||||||
|
|
||||||
fn output_json(map: serde_json::Map<String, serde_json::value::Value>,
|
fn output_json(
|
||||||
cache_header: Header<CacheControl>)
|
map: serde_json::Map<String, serde_json::value::Value>,
|
||||||
-> IronResult<Response> {
|
cache_header: Header<CacheControl>,
|
||||||
|
) -> IronResult<Response> {
|
||||||
let json = serde_json::to_string(&map).unwrap();
|
let json = serde_json::to_string(&map).unwrap();
|
||||||
let mime_json = Mime(TopLevel::Application,
|
let mime_json = Mime(
|
||||||
SubLevel::Json,
|
TopLevel::Application,
|
||||||
vec![(Attr::Charset, Value::Utf8)]);
|
SubLevel::Json,
|
||||||
|
vec![(Attr::Charset, Value::Utf8)],
|
||||||
|
);
|
||||||
Ok(Response::with((status::Ok, mime_json, cache_header, json)))
|
Ok(Response::with((status::Ok, mime_json, cache_header, json)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn output_html(map: serde_json::Map<String, serde_json::value::Value>,
|
fn output_html(
|
||||||
cache_header: Header<CacheControl>)
|
map: serde_json::Map<String, serde_json::value::Value>,
|
||||||
-> IronResult<Response> {
|
cache_header: Header<CacheControl>,
|
||||||
let mime_html = Mime(TopLevel::Text,
|
) -> IronResult<Response> {
|
||||||
SubLevel::Html,
|
let mime_html = Mime(
|
||||||
vec![(Attr::Charset, Value::Utf8)]);
|
TopLevel::Text,
|
||||||
|
SubLevel::Html,
|
||||||
|
vec![(Attr::Charset, Value::Utf8)],
|
||||||
|
);
|
||||||
let html = html!{
|
let html = html!{
|
||||||
head {
|
head {
|
||||||
title { : "iptoasn lookup" }
|
title { : "iptoasn lookup" }
|
||||||
|
@ -145,10 +156,11 @@ impl WebService {
|
||||||
Ok(Response::with((status::Ok, mime_html, cache_header, html)))
|
Ok(Response::with((status::Ok, mime_html, cache_header, html)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn output(output_type: OutputType,
|
fn output(
|
||||||
map: serde_json::Map<String, serde_json::value::Value>,
|
output_type: OutputType,
|
||||||
cache_header: Header<CacheControl>)
|
map: serde_json::Map<String, serde_json::value::Value>,
|
||||||
-> IronResult<Response> {
|
cache_header: Header<CacheControl>,
|
||||||
|
) -> IronResult<Response> {
|
||||||
match output_type {
|
match output_type {
|
||||||
OutputType::Json => Self::output_json(map, cache_header),
|
OutputType::Json => Self::output_json(map, cache_header),
|
||||||
_ => Self::output_html(map, cache_header),
|
_ => Self::output_html(map, cache_header),
|
||||||
|
@ -156,54 +168,77 @@ impl WebService {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ip_lookup(req: &mut Request) -> IronResult<Response> {
|
fn ip_lookup(req: &mut Request) -> IronResult<Response> {
|
||||||
let mime_text = Mime(TopLevel::Text,
|
let mime_text = Mime(
|
||||||
SubLevel::Plain,
|
TopLevel::Text,
|
||||||
vec![(Attr::Charset, Value::Utf8)]);
|
SubLevel::Plain,
|
||||||
let cache_header = Header(CacheControl(vec![CacheDirective::Public,
|
vec![(Attr::Charset, Value::Utf8)],
|
||||||
CacheDirective::MaxAge(TTL)]));
|
);
|
||||||
|
let cache_header = Header(CacheControl(
|
||||||
|
vec![CacheDirective::Public, CacheDirective::MaxAge(TTL)],
|
||||||
|
));
|
||||||
let ip_str = match req.extensions.get::<Router>().unwrap().find("ip") {
|
let ip_str = match req.extensions.get::<Router>().unwrap().find("ip") {
|
||||||
None => {
|
None => {
|
||||||
let response = Response::with((status::BadRequest,
|
let response = Response::with((
|
||||||
mime_text,
|
status::BadRequest,
|
||||||
cache_header,
|
mime_text,
|
||||||
"Missing IP address"));
|
cache_header,
|
||||||
|
"Missing IP address",
|
||||||
|
));
|
||||||
return Ok(response);
|
return Ok(response);
|
||||||
}
|
}
|
||||||
Some(ip_str) => ip_str,
|
Some(ip_str) => ip_str,
|
||||||
};
|
};
|
||||||
let ip = match IpAddr::from_str(ip_str) {
|
let ip = match IpAddr::from_str(ip_str) {
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
return Ok(Response::with((status::BadRequest,
|
return Ok(Response::with((
|
||||||
mime_text,
|
status::BadRequest,
|
||||||
cache_header,
|
mime_text,
|
||||||
"Invalid IP address")));
|
cache_header,
|
||||||
|
"Invalid IP address",
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
Ok(ip) => ip,
|
Ok(ip) => ip,
|
||||||
};
|
};
|
||||||
let asns = req.extensions.get::<ASNsMiddleware>().unwrap();
|
let asns = req.extensions.get::<ASNsMiddleware>().unwrap();
|
||||||
let mut map = serde_json::Map::new();
|
let mut map = serde_json::Map::new();
|
||||||
map.insert("ip".to_string(),
|
map.insert(
|
||||||
serde_json::value::Value::String(ip_str.to_string()));
|
"ip".to_string(),
|
||||||
|
serde_json::value::Value::String(ip_str.to_string()),
|
||||||
|
);
|
||||||
let found = match asns.lookup_by_ip(ip) {
|
let found = match asns.lookup_by_ip(ip) {
|
||||||
None => {
|
None => {
|
||||||
map.insert("announced".to_string(),
|
map.insert(
|
||||||
serde_json::value::Value::Bool(false));
|
"announced".to_string(),
|
||||||
|
serde_json::value::Value::Bool(false),
|
||||||
|
);
|
||||||
return Self::output(Self::accept_type(&req), map, cache_header);
|
return Self::output(Self::accept_type(&req), map, cache_header);
|
||||||
}
|
}
|
||||||
Some(found) => found,
|
Some(found) => found,
|
||||||
};
|
};
|
||||||
map.insert("announced".to_string(),
|
map.insert(
|
||||||
serde_json::value::Value::Bool(true));
|
"announced".to_string(),
|
||||||
map.insert("first_ip".to_string(),
|
serde_json::value::Value::Bool(true),
|
||||||
serde_json::value::Value::String(found.first_ip.to_string()));
|
);
|
||||||
map.insert("last_ip".to_string(),
|
map.insert(
|
||||||
serde_json::value::Value::String(found.last_ip.to_string()));
|
"first_ip".to_string(),
|
||||||
map.insert("as_number".to_string(),
|
serde_json::value::Value::String(found.first_ip.to_string()),
|
||||||
serde_json::value::Value::Number(serde_json::Number::from(found.number)));
|
);
|
||||||
map.insert("as_country_code".to_string(),
|
map.insert(
|
||||||
serde_json::value::Value::String(found.country.clone()));
|
"last_ip".to_string(),
|
||||||
map.insert("as_description".to_string(),
|
serde_json::value::Value::String(found.last_ip.to_string()),
|
||||||
serde_json::value::Value::String(found.description.clone()));
|
);
|
||||||
|
map.insert(
|
||||||
|
"as_number".to_string(),
|
||||||
|
serde_json::value::Value::Number(serde_json::Number::from(found.number)),
|
||||||
|
);
|
||||||
|
map.insert(
|
||||||
|
"as_country_code".to_string(),
|
||||||
|
serde_json::value::Value::String(found.country.clone()),
|
||||||
|
);
|
||||||
|
map.insert(
|
||||||
|
"as_description".to_string(),
|
||||||
|
serde_json::value::Value::String(found.description.clone()),
|
||||||
|
);
|
||||||
Self::output(Self::accept_type(&req), map, cache_header)
|
Self::output(Self::accept_type(&req), map, cache_header)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue