參考
- 依據Linux命令
- 以及sysconf下現有的iptables命令,詳見hsm_sysconf_server/src/sysconf_server.cpp中的firewall規則。
接口名稱
- firewall_manager
目的(現實)
- 根據網口直連獲取當前eth0和eth1的各種信息
- 保證設置的正確性? ? ??以及要針對管理口和服務口設計不同的初始化操作以及繼承的恢復操作。
- 并且要把防火墻規則通過數據庫存儲
目的(虛擬)
- 最終設計出封裝性良好的接口與實現
- 要經過詳細的額外設計保證其通用性
開始
第一步
- 首先需要學習以及嘗試使用iptables命令控制防火墻
介紹
- iptables 的主要功能是實現對網絡數據包進出設備及轉發的控制。當數據包需要進入設備、從設備中流出或者由該設備轉發、路由時,都可以使用 iptables 進行控制
- iptables 是集成在 Linux 內核中的包過濾防火墻系統。使用 iptables 可以添加、刪除具體的過濾規則,iptables 默認維護著 4 個表和 5 個鏈,所有的防火墻策略規則都被分別寫入這些表與鏈中。
- “四表”是指 iptables 的功能,默認的 iptable s規則表有 filter 表(過濾規則表)、nat 表(地址轉換規則表)、mangle(修改數據標記位規則表)、raw(跟蹤數據表規則表):
- filter 表:控制數據包是否允許進出及轉發,可以控制的鏈路有 INPUT、FORWARD 和 OUTPUT。
- nat 表:控制數據包中地址轉換,可以控制的鏈路有 PREROUTING、INPUT、OUTPUT 和 POSTROUTING。
- mangle:修改數據包中的原數據,可以控制的鏈路有 PREROUTING、INPUT、OUTPUT、FORWARD 和 POSTROUTING。
- raw:控制 nat 表中連接追蹤機制的啟用狀況,可以控制的鏈路有 PREROUTING、OUTPUT。
- “五鏈”是指內核中控制網絡的 NetFilter 定義的 5 個規則鏈。每個規則表中包含多個數據鏈:INPUT(入站數據過濾)、OUTPUT(出站數據過濾)、FORWARD(轉發數據過濾)、PREROUTING(路由前過濾)和POSTROUTING(路由后過濾),防火墻規則需要寫入到這些具體的數據鏈中。
2>/dev/null
- 2> / dev / null是什么意思?
iptables -c用法? ?
- 這使管理員能夠初始化規則的包和字節計數器(在INSERT,APPEND,REPLACE操作期間)
重啟防火墻
- Reloading iptables
2021年4月20日
今日存在的疑惑? ?2012年4月21日解決
execute_command干嘛的
#include "common/logging.h"#include <cstdarg>
#include <cstdio>
#include <string>namespace hsm {
namespace sys {int execute_command(const std::string &command, std::string *output = nullptr,bool redirect_stderr = false) {const auto &cmd = redirect_stderr ? command + " 2>&1" : command;auto pipe = popen(cmd.c_str(), "r");if (!pipe) {common::log_error("Can not exec command: {}", cmd);return -1;}// consume the output{char buffer[1024] = {0};while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {if (output) {output->append(buffer);}}}return pclose(pipe);
}} // namespace sys
} // namespace hsm
- Linux C popen()函數詳解
- C語言pclose()函數:關閉管道I/O
- linux shell中"2>&1"含義
#include <string>
#include <cstdio>int main(){FILE *fp;char buffer[1024] = {0};fp = popen("cat /etc/passwd","r");fgets(buffer,sizeof(buffer),fp);printf("%s",buffer);pclose(fp);
}
fmt::format是否實現 字符串替換 {}??
- format函數之幾種常規用法
- c++使用fmt::format格式化字符串
- c++ fmt 庫安裝和使用示例
- Fmt:更方便的 c++ format 庫
iptables -C啥意思
- -c, --set-counters?PKTS BYTES
- This enables the administrator to initialize the packet and byte counters of a rule (during?INSERT, APPEND, REPLACE?operations).
- -c, --set-counters PKTS BYTES? ?這使管理員能夠初始化一個規則的數據包和字節計數器(在INSERT、APPEND、REPLACE操作期間)。
{} 和 {1} 之間的區別
- {} 將輸入的參數進行替代
- {1} 將輸入的第一個參數進行替換
相關宏定義的聲明
SYS_CONF_OK | #define SYS_CONF_OK 0x0 |
SYS_CONF_SHELL_ERROR | #define SYS_CONF_SHELL_ERROR 0x2 |
FIREWALL_CONF_FILE_PATH | #define FIREWALL_CONF_FILE_PATH "/etc/firewall.conf" |
FIREWALL_RULES_FILE_PATH | #define FIREWALL_RULES_FILE_PATH "/etc/firewall.rules" |
FIREWALL_INIT_SCRIPT | #define FIREWALL_INIT_SCRIPT "/etc/init.d/11-firewall" |
SYS_CONF_UNKNOWN_TYPE | #define SYS_CONF_UNKNOWN_TYPE 0x4 |
std::unique_ptr<KeyValueConfStorage> firewall_config_storage;??KeyValueConfStorage結構
- ?storage.h 繼承了類? SysconfStorage
#pragma once#include "common/common.h"
#include "common/logging.h"#include <mutex>
#include <string>#include <json/json.h>namespace hsm {
namespace sys {class SysconfStorage {
public:explicit SysconfStorage(std::string persistence_file);virtual ~SysconfStorage() = default;virtual std::string serialize() = 0;bool sync(bool make_backup = true);void rollback();protected:std::string storage_file;std::string backup_file;std::mutex sync_data_mutex;
};class GlobalDataStorage : public SysconfStorage {
public:explicit GlobalDataStorage(std::string persistence_file);~GlobalDataStorage() override { sync(); }std::string serialize() override;bool update_device_status(size_t device_status, bool sync_now = true);bool register_ukey(const std::string &ukey_info, bool sync_now = true);bool unregister_ukey(const std::string &ukey_info, bool sync_now = true);const json &get(const std::string &key) const;json &get(const std::string &key);const json &get() const { return data; }private:json data;
};class KeyValueConfStorage : public SysconfStorage {
public:explicit KeyValueConfStorage(std::string persistence_file);~KeyValueConfStorage() override { sync(); }std::string serialize() override;bool set(const std::string &key, const std::string &value,bool sync_now = true);const std::string &get(const std::string &key);std::map<std::string, std::string> &get() { return data; }private:std::map<std::string, std::string> data;
};} // namespace sys
} // namespace hsm
- storage.cpp 頭文件中聲明函數的定義
#include "storage.h"
#include "common/filesystem.h"
#include "common/string_utils.h"#include <boost/filesystem.hpp>
#include <chrono>
#include <fstream>
#include <sstream>namespace hsm {
namespace sys {namespace fs = boost::filesystem;size_t get_time_us() {using namespace std::chrono;return duration_cast<microseconds>(system_clock::now().time_since_epoch()).count();
}SysconfStorage::SysconfStorage(std::string persistence_file): storage_file(std::move(persistence_file)),backup_file(storage_file + "-") {}bool SysconfStorage::sync(bool make_backup) {std::lock_guard<std::mutex> lock(sync_data_mutex);bool make_backup_ok = false;if (make_backup && fs::exists(storage_file)) {boost::system::error_code ec{};fs::rename(storage_file, backup_file, ec);if (ec) {common::log_error("Failed to sync, can not create backup file ({})",backup_file);return false;}make_backup_ok = true;}auto content = serialize();std::ofstream f(storage_file);f << content;if (f.fail()) {common::log_error("Failed to sync, can not write data to storage file ({})",storage_file);// revert storage fileif (make_backup_ok) {boost::system::error_code ec{};fs::rename(backup_file, storage_file, ec);if (ec) {common::log_fatal("Failed to sync, can not revert storage file ({}) from backup file ""({}), this is a unexpected fatal error",storage_file, backup_file);}}return false;}f.close();// sync filesystemsif (common::file_sync(storage_file) && common::file_sync(backup_file)) {common::log_debug("Files are synchronized");return true;}return false;
}void SysconfStorage::rollback() {boost::system::error_code ec{};fs::rename(backup_file, storage_file, ec);if (ec) {common::log_fatal("Can not revert storage file ({}) from backup file ""({}), this is a unexpected fatal error",storage_file, backup_file);}
}GlobalDataStorage::GlobalDataStorage(std::string persistence_file): SysconfStorage(std::move(persistence_file)) {{std::ifstream f(storage_file);if (f.is_open()) {std::stringstream ss;ss << f.rdbuf();data = json::parse(ss.str(), nullptr, false);}}if (!data.is_object()) {// try read backup filestd::ifstream f(backup_file);if (f.is_open()) {std::stringstream ss;ss << f.rdbuf();data = json::parse(ss.str(), nullptr, false);}if (!data.is_object()) { // initialize an empty storagedata = json();data["device_status"] = 0;data["ukey_list"] = json::object();sync();} else {sync(false);}}// simple checkif (!data.contains("device_status") || !data.contains("ukey_list")) {common::log_fatal("Invalid sysconf storage content");}
}std::string GlobalDataStorage::serialize() { return data.dump(); }bool GlobalDataStorage::update_device_status(size_t device_status,bool sync_now) {data["device_status"] = device_status;IF_LIKELY(sync_now) { return sync(); }return true;
}bool GlobalDataStorage::register_ukey(const std::string &ukey_info,bool sync_now) {json ukey_item;ukey_item["sn"] = ukey_info;ukey_item["time_us"] = get_time_us();data["ukey_list"][ukey_info] = std::move(ukey_item);IF_LIKELY(sync_now) { return sync(); }return true;
}bool GlobalDataStorage::unregister_ukey(const std::string &ukey_info,bool sync_now) {data["ukey_list"].erase(ukey_info);IF_LIKELY(sync_now) { return sync(); }return true;
}const json &GlobalDataStorage::get(const std::string &key) const {return data[key];
}json &GlobalDataStorage::get(const std::string &key) { return data[key]; }KeyValueConfStorage::KeyValueConfStorage(std::string persistence_file): SysconfStorage(std::move(persistence_file)) {{std::ifstream f(storage_file);if (f.is_open()) {std::stringstream ss;ss << f.rdbuf();data = common::parse_config(ss.str());}}if (data.empty()) {// try read backup filestd::ifstream f(backup_file);if (f.is_open()) {std::stringstream ss;ss << f.rdbuf();data = common::parse_config(ss.str());}// sync such valid backup dataif (!data.empty()) {sync(false);}}
}std::string KeyValueConfStorage::serialize() {if (data.empty()) {data["this_is_an_empty_config"] = "";}std::ostringstream ss;for (const auto &item : data) {ss << item.first << "=" << item.second << std::endl;}return ss.str();
}bool KeyValueConfStorage::set(const std::string &key, const std::string &value,bool sync_now) {data[key] = value;IF_LIKELY(sync_now) { return sync(); }return true;
}const std::string &KeyValueConfStorage::get(const std::string &key) {return data[key];
}} // namespace sys
} // namespace hsm
獲取eth0和eth1的各種信息
- getifaddrs()和struct ifaddrs的使用,獲取本機IP
- getifaddrs(3) — Linux manual page
- getifaddrs
- ifaddrs
- getifaddrs()--Return All Interface Addresses
任務
- 梳理邏輯,畫uml圖
通用模型設計(補充)
- ?限制每個客戶端最大并發數不超過3個(xshell終端)
- iptables?–A INPUT?–p tcp --dport 22?–s 192.168.1.0/24?–m connlimt?–connlimit-above 2?–j DROP
- 限制速度(-m limit --limit匹配速率| --burst緩沖數量)
- iptables?–A INPUT?–d?192.168.1.63?–m limit --limit 5/s --burst 100–j ACCEPT(在100個包內不限速,超過一百個包限制每秒只傳5個包)
- 查看當前的iptables的狀態
- 1,iptables -nL #默認查看filter表的狀態,如果需要查看其他表的狀態加上 -t 表名
- 2,iptables -nL --line-numbers #可以列出序列號,數據的插入和刪除和查看
- 3,iptables -nL --line-numbers --verbose #可以查看到包過濾的流量統計,訪問次數等
- 還原配置
- iptables-restore < /etc/sysconfig/iptables?
- 限制單個IP一分鐘內建立的連接數
- iptables -A INPUT -p tcp --syn --dport 80 -m connlimit --connlimit-above 25 -j REJECT
- 拒絕所有訪問
- iptables -A INPUT -j DROP #這個一般放到最后,不然會對前面的規則造成影響
- 針對端口開放(需要指明協議)
- iptables -I INPUT -p tcp --dport 22 -j ACCEPT
- 針對協議開放
- iptables -I INPUT -p imcp -j ACCEPT
- 根據時段限制訪問
- iptables -A INPUT -p tcp -m time --timestart 00:00 --timestop 02:00 -j DROP #這里的時間是指UTC時間記得換算
2021年4月22日
注意事項
1,數據庫存儲 防火墻的規則,將先前的命令進行細分
iptables -A INPUT -p tcp -s 10.159.1.0/24 --dport 22 -j ACCEPT
- 比如上述命令,字段細分 INPUT、目標設備(eth0/eth1)、端口 、跳轉行為(-j) 、ACCEPT等
2,同理? 也將上述字段 作為 函數的一個輸入參數?
2021年4月23號
- iptables -F #清除所有制定的規則
- iptables -X#清除用戶自定義的chain
- iptables -Z#將所有流量統計歸0
- 但是并非執行后就萬事大吉了。你仍然需要檢查規則是不是真的清空了,因為有的linux發行版上這個命令不會清除NAT表中的規則,此時只能手動清除:iptables -t NAT -F
- iptables工作原理及iptables命令行使用介紹
- 只允許 mac地址為aa:bb:cc:dd:ee:ff 的機器訪問本地ssh端口? ?iptables -A INPUT -m mac --mac-source aa:bb:cc:dd:ee:ff -p tcp --dport 22 -j ACCEPT
??
- ?C++ 獲取物理Mac地址
- C語言如何獲得變量的物理地址以及簡單的寫時拷貝測試
- linux中查看網卡mac地址
- MAC地址是什么
- 使用iptables基于MAC地址進行訪控
- Linux 查看網卡的MAC地址
linux查看網卡的部分具體命令
- /sbin/ifconfig | grep ether? ?ether是使用ifconfig查看到的網口信息,有些Linux發行版本的MAC地址字段為HWaddr,有些Linux發行版本的MAC地址字段為ether。根據實際情況選擇上面命令
-
如果想只提取網卡MAC地址,可以使用下面命令(用具體的網卡名替換xxx)? ? ? ifconfig xxx | grep -o -E '([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2}'
- ?cat?/sys/class/net/xxx/address查看
- dmesg | grep eth
?
和MAC有關的相關命令
- 1、阻止MAC地址為XX:XX:XX:XX:XX:XX主機的所有通信:? ?iptables -A INPUT -m mac --mac-source XX:XX:XX:XX:XX:XX -j DROP
- 2、允許MAC地址為XX:XX:XX:XX:XX:XX主機訪問22端口:? ?iptables -A INPUT -p tcp --destination-port 22 -m mac --mac-source XX:XX:XX:XX:XX:XX -j ACCEPT
參考鏈接
- Linux iptables命令詳解
- Linux防火墻netfilter的編程接口libiptc簡介
- Linux下使用libiptc庫編程下發規則
- linux筆記防火墻之iptables入門
- sysconf
- iptables編程文章列表
- iptables隨筆
- iptables-save
- iptables (簡體中文)
- iptables(8) - Linux man page ? iptables -c用法? ?
- iptables常用的命令匯總
- Linux 防火墻端口開放 屏蔽,IP開放屏蔽,協議開關 詳解Linux 防火墻? ??傳輸協議(如TCP、UDP、ICMP)和服務類型(如HTTP、FTP和SMTP)等
- Iptables 常用命令匯總
- iptables詳解及一些常用規則 yshenhn
- Linux iptables常用命令
- iptables
- 每天學習一個命令:iptables Linux 上的防火墻
- iptables工作原理及iptables命令行使用介紹
配置參考
- Linux下iptables防火墻配置詳解
- Linux防火墻配置(iptables, firewalld)
- ubuntu中防火墻iptables配置
- iptables 參數端口映射
?