fire_scope/
output.rs

1use crate::common::{IpFamily, OutputFormat};
2use crate::output_common::{make_header, write_list_nft, write_list_txt};
3use chrono::Local;
4use ipnet::IpNet;
5use std::{collections::BTreeSet, error::Error};
6
7/// IPv4/IPv6リストをファイルに書き出す
8/// 国コード用
9pub async fn write_ip_lists_to_files(
10    country_code: &str,
11    ipv4_list: &BTreeSet<IpNet>,
12    ipv6_list: &BTreeSet<IpNet>,
13    mode: &str,
14    format_enum: OutputFormat,
15) -> Result<(), Box<dyn Error + Send + Sync>> {
16    let now_str = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
17
18    match format_enum {
19        OutputFormat::Txt => {
20            // IPv4
21            let ipv4_file = format!("IPv4_{}.txt", country_code);
22            let header_v4 = make_header(&now_str, country_code, "N/A");
23            write_list_txt(&ipv4_file, ipv4_list, mode, &header_v4).await?;
24
25            // IPv6
26            let ipv6_file = format!("IPv6_{}.txt", country_code);
27            let header_v6 = make_header(&now_str, country_code, "N/A");
28            write_list_txt(&ipv6_file, ipv6_list, mode, &header_v6).await?;
29        }
30        OutputFormat::Nft => {
31            // IPv4
32            let ipv4_file = format!("IPv4_{}.nft", country_code);
33            let header_v4 = make_header(&now_str, country_code, "N/A");
34            write_list_nft(&ipv4_file, ipv4_list, mode, &header_v4).await?;
35
36            // IPv6
37            let ipv6_file = format!("IPv6_{}.nft", country_code);
38            let header_v6 = make_header(&now_str, country_code, "N/A");
39            write_list_nft(&ipv6_file, ipv6_list, mode, &header_v6).await?;
40        }
41    }
42    Ok(())
43}
44
45/// IPv4/IPv6リストをファイルに書き出す。
46/// AS番号用
47pub async fn write_as_ip_list_to_file(
48    as_number: &str,
49    family: IpFamily,
50    ipnets: &BTreeSet<IpNet>,
51    mode: &str,
52    format_enum: OutputFormat,
53) -> Result<(), Box<dyn Error + Send + Sync>> {
54    let now_str = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
55    let header = make_header(&now_str, "N/A", as_number);
56
57    match format_enum {
58        OutputFormat::Txt => {
59            let file_name = format!("AS_{}_{}.txt", as_number, family.as_str());
60            write_list_txt(&file_name, ipnets, mode, &header).await?;
61            println!(
62                "[output] Wrote/append TXT for AS_{} {}",
63                as_number,
64                family.as_str()
65            );
66        }
67        OutputFormat::Nft => {
68            let file_name = format!("AS_{}_{}.nft", as_number, family.as_str());
69            write_list_nft(&file_name, ipnets, mode, &header).await?;
70            println!(
71                "[output] Wrote/append NFT for AS_{} {}",
72                as_number,
73                family.as_str()
74            );
75        }
76    }
77    Ok(())
78}
79
80/// 国コード+AS番号の重複CIDRリストを書き出す
81/// Overlap用
82pub async fn write_overlap_to_file(
83    country_code: &str,
84    as_number: &str,
85    overlaps: &BTreeSet<IpNet>,
86    mode: &str,
87    format_enum: OutputFormat,
88) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
89    // IPv4 / IPv6 を仕分け
90    let overlaps_v4: BTreeSet<IpNet> = overlaps
91        .iter()
92        .cloned()
93        .filter(|net| matches!(net, IpNet::V4(_)))
94        .collect();
95
96    let overlaps_v6: BTreeSet<IpNet> = overlaps
97        .iter()
98        .cloned()
99        .filter(|net| matches!(net, IpNet::V6(_)))
100        .collect();
101
102    if overlaps_v4.is_empty() && overlaps_v6.is_empty() {
103        println!(
104            "[overlap] No overlap found for country={} and AS={}",
105            country_code, as_number
106        );
107        return Ok(());
108    }
109
110    // ファイル名などの準備
111    match format_enum {
112        OutputFormat::Txt => {
113            // IPv4
114            if !overlaps_v4.is_empty() {
115                let filename_v4 = format!("overlap_{}_{}_IPv4.txt", country_code, as_number);
116                let now_str = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
117                let header_v4 = make_header(&now_str, country_code, as_number);
118                write_list_txt(&filename_v4, &overlaps_v4, mode, &header_v4).await?;
119                println!("[overlap] Wrote/append IPv4 overlaps to: {}", filename_v4);
120            }
121            // IPv6
122            if !overlaps_v6.is_empty() {
123                let filename_v6 = format!("overlap_{}_{}_IPv6.txt", country_code, as_number);
124                let now_str = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
125                let header_v6 = make_header(&now_str, country_code, as_number);
126                write_list_txt(&filename_v6, &overlaps_v6, mode, &header_v6).await?;
127                println!("[overlap] Wrote/append IPv6 overlaps to: {}", filename_v6);
128            }
129        }
130        OutputFormat::Nft => {
131            // IPv4
132            if !overlaps_v4.is_empty() {
133                let filename_v4 = format!("overlap_{}_{}_IPv4.nft", country_code, as_number);
134                let now_str = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
135                let header_v4 = make_header(&now_str, country_code, as_number);
136                write_list_nft(&filename_v4, &overlaps_v4, mode, &header_v4).await?;
137                println!(
138                    "[overlap] Wrote/append IPv4 overlaps nft to: {}",
139                    filename_v4
140                );
141            }
142            // IPv6
143            if !overlaps_v6.is_empty() {
144                let filename_v6 = format!("overlap_{}_{}_IPv6.nft", country_code, as_number);
145                let now_str = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
146                let header_v6 = make_header(&now_str, country_code, as_number);
147                write_list_nft(&filename_v6, &overlaps_v6, mode, &header_v6).await?;
148                println!(
149                    "[overlap] Wrote/append IPv6 overlaps nft to: {}",
150                    filename_v6
151                );
152            }
153        }
154    }
155
156    Ok(())
157}