Rust: как конвертировать SocketAddr в IpNetwork? - PullRequest
0 голосов
/ 02 февраля 2020

Используя Diesel и Rocket, я хочу иметь возможность регистрировать IP-адреса, с которых поступают запросы. Здесь - аналогичное обсуждение, но без заключения. Дизель отображает тип Postgres inet на IpNetwork, но Rocket возвращает SocketAddr из данных запроса. Как конфертировать SocketAddr в IpNetwork?

models.rs :

#![allow(proc_macro_derive_resolution_fallback)]
use crate::schema::bs_date_forecast;

use chrono::{NaiveDate, NaiveDateTime};
use ipnetwork::IpNetwork;
use diesel::prelude::*;

#[derive(Queryable, Insertable, Serialize, Deserialize)]
#[table_name="bs_date_forecast"]
pub struct BsDateForecast {
    pub id: Option<i32>,
    pub predicted_date: NaiveDate,
    pub seer_ip: IpNetwork,
    pub created_timestamp: NaiveDateTime,  // Defined automatically at the database level
}

impl BsDateForecast {
    pub fn create(forecast: BsDateForecast,
                  conn: &PgConnection) -> Vec<BsDateForecast> {
        diesel::insert_into(bs_date_forecast::table)
            .values(&forecast)
            .get_results(conn)
            .expect("Error creating record")
    }
}

rout.rs :

#[post("/predictions", format = "application/json", data = "<prediction>")]
pub fn create(prediction: Json<BsDateForecast>,
              conn: DbConn,
              user_ip: SocketAddr) -> Json<Vec<BsDateForecast>> {
    let insert = BsDateForecast{
        id: None,
        seer_ip: user_ip.to_string(),  // How to get IpNetwork here???
        ..prediction.into_inner()
    };
    Json(BsDateForecast::create(insert, &conn))
}

1 Ответ

1 голос
/ 02 февраля 2020

Тип INET может хранить su bnet (включая маску su bnet) или один хост. Тип IpNetwork предназначен для хранения su bnet, но один хост можно сохранить способом Postgres, указав префикс полной длины.

SocketAddr - это IpAddr плюс номер порта.

Итак, преобразование таково: получите IP-часть SocketAddr, создайте IpNetwork из нее, указав правильный префикс.

Сложность заключается в том, что префикс для IP4 и IP6 отличается.

fn socket_addr_to_ip_network(socket_addr: &SocketAddr) -> IpNetwork {
  let ip = socket_addr.ip();
  IpNetwork::new(ip, single_host_prefix(ip))
    .expect("single_host_prefix created invalid prefix")
}
fn single_host_prefix(ip_addr: &IpAddr) -> u8 {
  match ip_addr { &IpAddr::V4(_) => 32, &IpAddr::V6(_) => 128 }
}
...