feat: update ipset
This commit is contained in:
165
src/ipset.rs
165
src/ipset.rs
@@ -1,40 +1,74 @@
|
|||||||
use rust_util::{opt_result, simple_error, XResult};
|
use rust_util::{opt_result, simple_error, XResult};
|
||||||
|
use std::error::Error;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
const CMD_IPSET: &str = "ipset";
|
const CMD_IPSET: &str = "ipset";
|
||||||
|
|
||||||
// TODO
|
pub struct IpSet {
|
||||||
// list names
|
|
||||||
// list ipsetname
|
|
||||||
// add
|
|
||||||
// del
|
|
||||||
|
|
||||||
struct IpSet {
|
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IpSet {
|
impl IpSet {
|
||||||
pub fn list_names() -> Vec<String> {
|
pub fn new(name: &str) -> XResult<IpSet> {
|
||||||
vec![]
|
if name.is_empty() {
|
||||||
|
return simple_error!("ipset name cannot be empty");
|
||||||
|
}
|
||||||
|
Ok(IpSet {
|
||||||
|
name: String::from(name),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list(&self) -> Vec<String> {
|
pub fn list_names() -> XResult<Vec<String>> {
|
||||||
vec![]
|
list_names()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(&self, ip: &str) -> () {}
|
|
||||||
|
|
||||||
pub fn del(&self, ip: &str) -> () {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_names() {}
|
impl IpSet {
|
||||||
|
pub fn list(&self) -> XResult<Vec<String>> {
|
||||||
|
let (stdout, _stderr) = execute_ipset(&["list", &self.name])?;
|
||||||
|
let ipset_list_ips = opt_result!(
|
||||||
|
String::from_utf8(stdout.clone()),
|
||||||
|
"Parse output: {} failed: {}",
|
||||||
|
String::from_utf8_lossy(&stdout)
|
||||||
|
);
|
||||||
|
Ok(parse_ipset_list_ips(&ipset_list_ips))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add(&self, ip: &str) -> XResult<()> {
|
||||||
|
add_ipset(&self.name, ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn del(&self, ip: &str) -> XResult<()> {
|
||||||
|
del_ipset(&self.name, ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list_names() -> XResult<Vec<String>> {
|
||||||
|
let (stdout, _stderr) = execute_ipset(&["list", "-n"])?;
|
||||||
|
let ipset_list_names = opt_result!(
|
||||||
|
String::from_utf8(stdout.clone()),
|
||||||
|
"Parse output: {} failed: {}",
|
||||||
|
String::from_utf8_lossy(&stdout)
|
||||||
|
);
|
||||||
|
Ok(parse_ipset_list(&ipset_list_names))
|
||||||
|
}
|
||||||
|
|
||||||
fn list_ipset(ipset_name: &str) {}
|
fn list_ipset(ipset_name: &str) {}
|
||||||
|
|
||||||
fn add_ipset(ipset_name: &str, ip: &str) {}
|
fn add_ipset(ipset_name: &str, ip: &str) -> XResult<()> {
|
||||||
|
if let Err(err) = execute_ipset(&["add", ipset_name, ip]) {
|
||||||
|
return check_result(err, &["cannot be added to the set: it's already added"]);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn del_ipset(ipset_name: &str, ip: &str) {}
|
fn del_ipset(ipset_name: &str, ip: &str) -> XResult<()> {
|
||||||
|
if let Err(err) = execute_ipset(&["del", ipset_name, ip]) {
|
||||||
|
return check_result(err, &["cannot be deleted from the set: it's not added"]);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn execute_ipset<I, S>(args: I) -> XResult<(Vec<u8>, Vec<u8>)>
|
fn execute_ipset<I, S>(args: I) -> XResult<(Vec<u8>, Vec<u8>)>
|
||||||
where
|
where
|
||||||
@@ -46,9 +80,100 @@ where
|
|||||||
let cmd_output = opt_result!(cmd_ipset.output(), "Execute ipset with failed: {}");
|
let cmd_output = opt_result!(cmd_ipset.output(), "Execute ipset with failed: {}");
|
||||||
if !cmd_output.status.success() {
|
if !cmd_output.status.success() {
|
||||||
return simple_error!(
|
return simple_error!(
|
||||||
"Execute ipset not failed, exit code: {:?}",
|
"Execute ipset not failed, exit code: {:?}, stdout: {}, stderr: {}",
|
||||||
cmd_output.status.code()
|
cmd_output.status.code(),
|
||||||
|
String::from_utf8_lossy(&cmd_output.stdout),
|
||||||
|
String::from_utf8_lossy(&cmd_output.stderr)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Ok((cmd_output.stdout, cmd_output.stderr))
|
Ok((cmd_output.stdout, cmd_output.stderr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_result(e: Box<dyn Error>, allowed_messages: &[&str]) -> XResult<()> {
|
||||||
|
let e_msg = e.to_string();
|
||||||
|
for allowed_message in allowed_messages {
|
||||||
|
if e_msg.contains(allowed_message) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_ipset_list(ipset_list: &str) -> Vec<String> {
|
||||||
|
ipset_list
|
||||||
|
.split('\n')
|
||||||
|
.map(|name| name.trim())
|
||||||
|
.filter(|name| !name.is_empty())
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_ipset_list_ips(ipset_list: &str) -> Vec<String> {
|
||||||
|
let mut result = vec![];
|
||||||
|
let mut is_after_members = false;
|
||||||
|
ipset_list.split('\n').for_each(|ln| {
|
||||||
|
let ln = ln.trim();
|
||||||
|
if !ln.is_empty() {
|
||||||
|
if is_after_members {
|
||||||
|
result.push(ln.to_string());
|
||||||
|
} else {
|
||||||
|
if ln.to_lowercase() == "members:" {
|
||||||
|
is_after_members = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_ipset_list() {
|
||||||
|
let empty_vec: Vec<String> = vec![];
|
||||||
|
assert_eq!(empty_vec, parse_ipset_list(""));
|
||||||
|
assert_eq!(vec!["test".to_string()], parse_ipset_list("test\n"));
|
||||||
|
assert_eq!(
|
||||||
|
vec!["allowipset".to_string()],
|
||||||
|
parse_ipset_list("allowipset")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
vec!["allowipset".to_string()],
|
||||||
|
parse_ipset_list("allowipset\n")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_ipset_list_ips_1() {
|
||||||
|
let ipset_list_ips = r"Name: allowipset
|
||||||
|
Type: hash:ip
|
||||||
|
Revision: 1
|
||||||
|
Header: family inet hashsize 1024 maxelem 65536
|
||||||
|
Size in memory: 21264
|
||||||
|
References: 6
|
||||||
|
Members:
|
||||||
|
115.195.128.60
|
||||||
|
36.18.233.45
|
||||||
|
36.27.0.166
|
||||||
|
60.186.198.141
|
||||||
|
223.104.246.130";
|
||||||
|
let ips = parse_ipset_list_ips(ipset_list_ips);
|
||||||
|
assert_eq!(5, ips.len());
|
||||||
|
assert_eq!("115.195.128.60", &ips[0]);
|
||||||
|
assert_eq!("36.18.233.45", &ips[1]);
|
||||||
|
assert_eq!("36.27.0.166", &ips[2]);
|
||||||
|
assert_eq!("60.186.198.141", &ips[3]);
|
||||||
|
assert_eq!("223.104.246.130", &ips[4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_ipset_list_ips_2() {
|
||||||
|
let ipset_list_ips = r"Size in memory: 30688
|
||||||
|
References: 6
|
||||||
|
Members:
|
||||||
|
36.28.155.64
|
||||||
|
36.20.56.144
|
||||||
|
";
|
||||||
|
let ips = parse_ipset_list_ips(ipset_list_ips);
|
||||||
|
assert_eq!(2, ips.len());
|
||||||
|
assert_eq!("36.28.155.64", &ips[0]);
|
||||||
|
assert_eq!("36.20.56.144", &ips[1]);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user