rocket_client_addr/
client_real_addr.rs1use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
2
3use rocket::{
4 http::Status,
5 outcome::Outcome,
6 request::{self, FromRequest, Request},
7};
8
9#[derive(Debug, Clone)]
11pub struct ClientRealAddr {
12 pub ip: IpAddr,
14}
15
16fn from_request(request: &Request<'_>) -> Option<ClientRealAddr> {
17 match request.real_ip() {
18 Some(ip) => Some(ClientRealAddr {
19 ip,
20 }),
21 None => {
22 let forwarded_for_ip: Option<&str> = request.headers().get("x-forwarded-for").next(); match forwarded_for_ip {
25 Some(forwarded_for_ip) => {
26 let forwarded_for_ip = forwarded_for_ip.split(',').next(); match forwarded_for_ip {
29 Some(forwarded_for_ip) => match forwarded_for_ip.trim().parse::<IpAddr>() {
30 Ok(ip) => Some(ClientRealAddr {
31 ip,
32 }),
33 Err(_) => request.remote().map(|addr| ClientRealAddr {
34 ip: addr.ip()
35 }),
36 },
37 None => request.remote().map(|addr| ClientRealAddr {
38 ip: addr.ip()
39 }),
40 }
41 },
42 None => request.remote().map(|addr| ClientRealAddr {
43 ip: addr.ip()
44 }),
45 }
46 },
47 }
48}
49
50#[rocket::async_trait]
51impl<'r> FromRequest<'r> for ClientRealAddr {
52 type Error = ();
53
54 async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
55 match from_request(request) {
56 Some(client_addr) => Outcome::Success(client_addr),
57 None => Outcome::Forward(Status::BadRequest),
58 }
59 }
60}
61
62#[rocket::async_trait]
63impl<'r> FromRequest<'r> for &'r ClientRealAddr {
64 type Error = ();
65
66 async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
67 let cache: &Option<ClientRealAddr> = request.local_cache(|| from_request(request));
68
69 match cache.as_ref() {
70 Some(client_addr) => Outcome::Success(client_addr),
71 None => Outcome::Forward(Status::BadRequest),
72 }
73 }
74}
75
76impl ClientRealAddr {
77 pub fn get_ipv4(&self) -> Option<Ipv4Addr> {
79 match &self.ip {
80 IpAddr::V4(ipv4) => Some(*ipv4),
81 IpAddr::V6(ipv6) => ipv6.to_ipv4(),
82 }
83 }
84
85 pub fn get_ipv4_string(&self) -> Option<String> {
87 match &self.ip {
88 IpAddr::V4(ipv4) => Some(ipv4.to_string()),
89 IpAddr::V6(ipv6) => ipv6.to_ipv4().map(|ipv6| ipv6.to_string()),
90 }
91 }
92
93 pub fn get_ipv6(&self) -> Ipv6Addr {
95 match &self.ip {
96 IpAddr::V4(ipv4) => ipv4.to_ipv6_mapped(),
97 IpAddr::V6(ipv6) => *ipv6,
98 }
99 }
100
101 pub fn get_ipv6_string(&self) -> String {
103 match &self.ip {
104 IpAddr::V4(ipv4) => ipv4.to_ipv6_mapped().to_string(),
105 IpAddr::V6(ipv6) => ipv6.to_string(),
106 }
107 }
108}