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