Страница 1 из 1

пример расширенного ARP-сервера на Python

Добавлено: 06 дек 2025, 21:54
ya
Установка библиотек: scapy, pysnmp

Код: Выделить всё

pip install scapy pysnmp
Файл конфигурации (config.json)

Код: Выделить всё

{
  "interfaces": ["eth0"],
  "arp_table": {
    "192.168.1.100": "00:11:22:33:44:55",
    "192.168.1.101": "00:11:22:33:44:66"
  },
  "network_scan": {
    "enabled": true,
    "subnet": "192.168.1.0/24"
  },
  "snmp": {
    "enabled": true,
    "host": "192.168.1.1",
    "community": "public"
  }
}
Основной скрипт (arp_server.py)

Код: Выделить всё

import json
import logging
import threading
import time
from scapy.all import *
from pysnmp.hlapi import *

# Настройка логирования
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# Загрузка конфигурации
with open('config.json') as f:
    config = json.load(f)

interfaces = config.get('interfaces', ['eth0'])
arp_table = dict(config.get('arp_table', {}))
network_scan_config = config.get('network_scan', {})
snmp_config = config.get('snmp', {})

# Обратные словари для проверки MAC по IP
ip_to_mac = dict(arp_table)

# Функция для сканирования сети и обновления таблицы
def scan_network(subnet):
    print(f"Scanning network {subnet} for active hosts...")
    hosts = []
    # Используем nmap для поиска активных хостов
    result = subprocess.run(["nmap", "-sn", subnet], capture_output=True, text=True)
    for line in result.stdout.splitlines():
        if "Nmap scan report for" in line:
            ip = line.split()[-1]
            hosts.append(ip)
    return hosts

# Функция для автоматического обновления таблицы устройств
def auto_update_table():
    if network_scan_config.get('enabled', False):
        subnet = network_scan_config.get('subnet', '')
        while True:
            hosts = scan_network(subnet)
            for ip in hosts:
                # Получаем MAC-адрес через ARP
                ans, unans = sr(ARP(pdst=ip), timeout=2, verbose=False)
                for sent, received in ans:
                    ip_addr = received.psrc
                    mac_addr = received.hwsrc
                    # Обновляем таблицу
                    arp_table[ip_addr] = mac_addr
                    ip_to_mac[ip_addr] = mac_addr
                    logging.info(f"Обновлена запись: {ip_addr} - {mac_addr}")
            time.sleep(300)  # обновлять каждые 5 минут

# Функция для отправки SNMP Trap (пример)
def send_snmp_trap(message):
    if not snmp_config.get('enabled', False):
        return
    target = snmp_config.get('host')
    community = snmp_config.get('community')
    errorIndication, errorStatus, errorIndex, varBinds = next(
        sendNotification(
            SnmpEngine(),
            CommunityData(community),
            UdpTransportTarget((target, 162)),
            ContextData(),
            'trap',
            NotificationType(
                ObjectIdentity('1.3.6.1.6.3.1.1.5.1')  # пример OID
            )
        )
    )
    if errorIndication:
        logging.error(f"SNMP Error: {errorIndication}")

# Проверка фальшивых ARP-ответов
def validate_arp(pkt):
    if ARP in pkt:
        src_ip = pkt[ARP].psrc
        src_mac = pkt[Ether].src
        # Проверяем, есть ли запись в таблице
        expected_mac = ip_to_mac.get(src_ip)
        if expected_mac:
            if src_mac != expected_mac:
                # Подозрительный ARP
                logging.warning(f"Подозрительный ARP: IP {src_ip} ожидает MAC {expected_mac}, получен {src_mac}")
                # Можно предпринять меры: блокировать, логировать, оповещать
                send_snmp_trap(f"Подозрительный ARP: IP {src_ip} MAC {src_mac}")
                return False
        else:
            # Новое устройство, добавить в таблицу
            arp_table[src_ip] = src_mac
            ip_to_mac[src_ip] = src_mac
            logging.info(f"Добавлено новое устройство: {src_ip} - {src_mac}")
    return True

# Обработчик ARP-пакетов
def handle_arp(pkt):
    if ARP in pkt and pkt[ARP].op == 1:  # ARP-запрос
        src_ip = pkt[ARP].psrc
        dst_ip = pkt[ARP].pdst
        src_mac = pkt[Ether].src
        logging.info(f"ARP запрос: {src_ip} запрашивает {dst_ip} ({src_mac})")
        
        # Проверка валидности ARP
        if not validate_arp(pkt):
            logging.info("Фальшивый ARP-ответ или подозрительный запрос, игнорируем")
            return

        # Проверка, есть ли ответ в таблице
        if dst_ip in ip_to_mac:
            target_mac = ip_to_mac[dst_ip]
            ether = Ether(dst=pkt[Ether].src, src=target_mac)
            arp_reply = ARP(op=2, hwsrc=target_mac, psrc=dst_ip,
                            hwdst=pkt[Ether].src, pdst=src_ip)
            reply_pkt = ether / arp_reply
            sendp(reply_pkt, iface=pkt.sniffed_on, verbose=False)
            logging.info(f"Отправлен ARP-ответ: {dst_ip} -> {src_ip}")
        else:
            logging.warning(f"Нет записи для IP {dst_ip} в таблице")

# Основная функция
def main():
    # Запуск автоматического обновления таблицы в отдельном потоке
    updater_thread = threading.Thread(target=auto_update_table, daemon=True)
    updater_thread.start()

    print("Расширенный ARP-сервер запущен")
    for iface in interfaces:
        print(f"Слушание интерфейса: {iface}")
        sniff(filter="arp", prn=handle_arp, iface=iface)

if __name__ == "__main__":
    main()
Запуск

Код: Выделить всё

sudo python3 extended_arp_server.py

Что делает этот скрипт:
Автоматическое обновление таблицы:
Периодически сканирует сеть (nmap) и узнает активные устройства.
Обновляет IP-MAC таблицу.
Работает в отдельном потоке, не мешая основной работе.
Защита от фальшивых ARP:
Проверяет MAC-адрес по IP при получении ARP-запросов.
В случае несоответствия — логирует и отправляет SNMP-trap.
Можно расширить, добавив блокировки или уведомления.
Интеграция с оборудованием:
Отправка SNMP-трейпов при обнаружении подозрительных ARP.
Можно расширить для управления оборудованием через SNMP, REST API.
Итог
Этот скрипт — база для надежного ARP-сервера с автоматическим управлением и защитой. Его можно расширять под конкретные задачи, добавляя, например, управление списками доверенных устройств, интеграцию с SIEM, автоматическую блокировку и т.п.

Re: пример расширенного ARP-сервера на C++

Добавлено: 06 дек 2025, 22:01
ya
расширенный ARP-сервер с автоматическим обновлением таблицы, защитой от злоумышленников и интеграцией с сетевым оборудованием на C++ (g++ v11) — это более сложная задача, так как многие из функций требуют низкоуровневого доступа к сети и работы с протоколами.

Прослушивание ARP-пакетов (используя libpcap)
Проверка ARP-запросов и ответов
Обновление таблицы устройств
Отправка SNMP Trap (используя net-snmp)
Простая автоматическая проверка и логика защиты

Код: Выделить всё

sudo apt-get install libpcap-dev libnet-snmp-dev libnet-dev

Код: Выделить всё

#include <pcap.h>
#include <iostream>
#include <unordered_map>
#include <string>
#include <thread>
#include <chrono>
#include <mutex>
#include <netinet/if_ether.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <snmp/snmp.h>
#include <snmp/snmp_api.h>

// Таблица IP -> MAC
std::unordered_map<std::string, std::string> arp_table;
std::mutex table_mutex;

// Время обновления таблицы
void update_arp_table() {
    while (true) {
        // Тут можно реализовать сканирование сети и обновление таблицы
        // Например, отправлять ARP-запросы и слушать ответы
        // Для упрощения этого примера — пропустим
        std::this_thread::sleep_for(std::chrono::minutes(5));
    }
}

// Отправка SNMP Trap (заглушка)
void send_snmp_trap(const std::string& message) {
    // Инициализация SNMP и отправка trap
    // Реальное использование требует настройки SNMP API
    // Это пример-заглушка
    std::cout << "[SNMP Trap] " << message << std::endl;
}

// Обработка ARP пакета
void handle_packet(const u_char *args, const struct pcap_pkthdr *header, const u_char *packet) {
    struct ether_header *eth_header = (struct ether_header *) packet;

    if (ntohs(eth_header->ether_type) == ETHERTYPE_ARP) {
        struct ether_arp *arp_pkt = (struct ether_arp *)(packet + sizeof(struct ether_header));

        // Получение IP и MAC из ARP-запроса
        char sender_ip[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, arp_pkt->arp_spa, sender_ip, INET_ADDRSTRLEN);
        char sender_mac[18];
        snprintf(sender_mac, sizeof(sender_mac), "%02x:%02x:%02x:%02x:%02x:%02x",
                 arp_pkt->arp_sha[0], arp_pkt->arp_sha[1], arp_pkt->arp_sha[2],
                 arp_pkt->arp_sha[3], arp_pkt->arp_sha[4], arp_pkt->arp_sha[5]);

        std::string ip_str(sender_ip);
        std::string mac_str(sender_mac);

        {
            // Проверка и обновление таблицы
            std::lock_guard<std::mutex> lock(table_mutex);
            auto it = arp_table.find(ip_str);
            if (it != arp_table.end()) {
                if (it->second != mac_str) {
                    // Обнаружена фальшивка
                    std::cerr << "Подозрительный ARP: IP " << ip_str << " ожидает MAC " << it->second
                              << ", получен " << mac_str << std::endl;
                    send_snmp_trap("Подозрительный ARP: IP " + ip_str + " MAC " + mac_str);
                }
            } else {
                arp_table[ip_str] = mac_str;
                std::cout << "Добавлено устройство: " << ip_str << " - " << mac_str << std::endl;
            }
        }

        // Можно добавить отправку ARP-ответа
        // Для этого нужно формировать Ethernet + ARP пакеты с libpcap
        // Это более сложная задача и требует подробных настроек
    }
}

int main() {
    char errbuf[PCAP_ERRBUF_SIZE];
    pcap_t *handle;

    // Открываем сетевой интерфейс
    handle = pcap_open_live("eth0", 65536, 1, 1000, errbuf);
    if (handle == nullptr) {
        std::cerr << "Ошибка открытия интерфейса: " << errbuf << std::endl;
        return 1;
    }

    // Запускаем поток обновления таблицы
    std::thread updater_thread(update_arp_table);
    updater_thread.detach();

    // Настраиваем фильтр для ARP
    struct bpf_program fp;
    if (pcap_compile(handle, &fp, "arp", 0, PCAP_NETMASK_UNKNOWN) == -1) {
        std::cerr << "Ошибка компиляции фильтра" << std::endl;
        return 1;
    }
    if (pcap_setfilter(handle, &fp) == -1) {
        std::cerr << "Ошибка установки фильтра" << std::endl;
        return 1;
    }

    std::cout << "Запуск прослушки ARP-пакетов на интерфейсе eth0..." << std::endl;

    // Цикл прослушки
    while (true) {
        pcap_dispatch(handle, -1, handle_packet, nullptr);
    }

    pcap_close(handle);
    return 0;
}
В этом примере:
Используется libpcap для прослушивания ARP-пакетов
Обрабатываются ARP-запросы, и проверяется их подлинность
В случае подозрительных ARP-ответов вызывается функция отправки SNMP Trap
Таблица IP-MAC хранится в std::unordered_map с мьютексом для потокобезопасности
Функция update_arp_table() — заготовка для автоматического обновления таблицы (можно реализовать через ARP-запросы или сетевое сканирование)
Чтобы отправлять ARP-ответы или управлять сетью, потребуется более сложная работа с libpcap или libnet.

Re: пример расширенного ARP-сервера на C++

Добавлено: 06 дек 2025, 22:09
ya

Код: Выделить всё

libpcap-dev, libnet-dev, libsnmp-dev
Структура файлов

Код: Выделить всё

arp_monitor/
├── include/
│   ├── EventListener.h
│   ├── ArpTable.h
│   ├── ArpPacketFactory.h
│   ├── SnmpSender.h
│   └── ArpMonitor.h
├── src/
│   ├── EventListener.cpp
│   ├── ArpTable.cpp
│   ├── ArpPacketFactory.cpp
│   ├── SnmpSender.cpp
│   ├── ArpMonitor.cpp
│   └── main.cpp
└── Makefile
Заголовочные файлы

include/EventListener.h

Код: Выделить всё

#ifndef EVENT_LISTENER_H
#define EVENT_LISTENER_H

#include <string>

class EventListener {
public:
    virtual void onSuspiciousARP(const std::string& ip, const std::string& mac) = 0;
    virtual ~EventListener() = default;
};

#endif // EVENT_LISTENER_H
include/ArpTable.h

Код: Выделить всё

#ifndef ARP_TABLE_H
#define ARP_TABLE_H

#include <unordered_map>
#include <string>
#include <mutex>
#include <stdexcept>

class ArpTable {
private:
    std::unordered_map<std::string, std::string> table_;
    std::mutex mutex_;

    ArpTable() = default;

public:
    static ArpTable& getInstance() {
        static ArpTable instance;
        return instance;
    }

    void update(const std::string& ip, const std::string& mac) {
        std::lock_guard<std::mutex> lock(mutex_);
        auto it = table_.find(ip);
        if (it != table_.end() && it->second != mac) {
            throw std::runtime_error("Suspicious ARP: " + ip);
        }
        table_[ip] = mac;
    }

    std::string getMac(const std::string& ip) {
        std::lock_guard<std::mutex> lock(mutex_);
        auto it = table_.find(ip);
        return (it != table_.end()) ? it->second : "";
    }
};

#endif // ARP_TABLE_H
include/ArpPacketFactory.h

Код: Выделить всё

#ifndef ARP_PACKET_FACTORY_H
#define ARP_PACKET_FACTORY_H

#include <libnet.h>
#include <string>

class ArpPacketFactory {
public:
    static void sendArpReply(const std::string& src_mac, const std::string& src_ip,
                             const std::string& dst_mac, const std::string& dst_ip,
                             const std::string& iface);
    static void sendArpRequest(const std::string& target_ip, const std::string& src_mac,
                               const std::string& src_ip, const std::string& iface);
};

#endif // ARP_PACKET_FACTORY_H
include/SnmpSender.h

Код: Выделить всё

#ifndef SNMP_SENDER_H
#define SNMP_SENDER_H

#include <string>

class SnmpSender {
public:
    static void sendTrap(const std::string& message);
};

#endif // SNMP_SENDER_H
include/ArpMonitor.h

Код: Выделить всё

#ifndef ARP_MONITOR_H
#define ARP_MONITOR_H

#include "EventListener.h"
#include <pcap.h>
#include <thread>
#include <vector>
#include <memory>

class ArpMonitor {
private:
    std::string iface_;
    std::vector<std::shared_ptr<EventListener>> listeners_;
    std::thread monitor_thread_;
    std::atomic<bool> running_{false};

    void monitorLoop();

public:
    explicit ArpMonitor(const std::string& iface);
    void start();
    void stop();
    void addListener(std::shared_ptr<EventListener> listener);
};

#endif // ARP_MONITOR_H
Реализация файлов

src/EventListener.cpp

Код: Выделить всё

#include "EventListener.h"
// Реализация не нужна, интерфейс
src/ArpTable.cpp

Код: Выделить всё

#include "ArpTable.h"
// Реализация уже в заголовке как inline
src/ArpPacketFactory.cpp

Код: Выделить всё

#include "ArpPacketFactory.h"
#include <libnet.h>
#include <iostream>
#include <cstring>

void ArpPacketFactory::sendArpReply(const std::string& src_mac, const std::string& src_ip,
                                    const std::string& dst_mac, const std::string& dst_ip,
                                    const std::string& iface) {
    libnet_t *l;
    char errbuf[LIBNET_ERRBUF_SIZE];

    l = libnet_init(LIBNET_LINK, iface.c_str(), errbuf);
    if (l == nullptr) {
        std::cerr << "libnet init failed: " << errbuf << std::endl;
        return;
    }

    uint8_t smac[6], dmac[6];
    uint32_t sip, dip;

    sscanf(src_mac.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
           &smac[0], &smac[1], &smac[2], &smac[3], &smac[4], &smac[5]);
    sscanf(dst_mac.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
           &dmac[0], &dmac[1], &dmac[2], &dmac[3], &dmac[4], &dmac[5]);
    inet_pton(AF_INET, src_ip.c_str(), &sip);
    inet_pton(AF_INET, dst_ip.c_str(), &dip);

    libnet_autobuild_ethernet(dmac, ETHERTYPE_ARP, l);
    libnet_build_arp(ARPHRD_ETHER, ETHERTYPE_IP, 6, 4,
                     ARPOP_REPLY, smac, &sip, dmac, &dip,
                     nullptr, 0, l);

    int bytes = libnet_write(l);
    if (bytes == -1) {
        std::cerr << "libnet_write failed: " << libnet_geterror(l) << std::endl;
    }
    libnet_destroy(l);
}

void ArpPacketFactory::sendArpRequest(const std::string& target_ip, const std::string& src_mac,
                                      const std::string& src_ip, const std::string& iface) {
    libnet_t *l;
    char errbuf[LIBNET_ERRBUF_SIZE];

    l = libnet_init(LIBNET_LINK, iface.c_str(), errbuf);
    if (l == nullptr) {
        std::cerr << "libnet init failed: " << errbuf << std::endl;
        return;
    }

    uint8_t smac[6], dmac[6];
    uint32_t sip, dip;

    sscanf(src_mac.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
           &smac[0], &smac[1], &smac[2], &smac[3], &smac[4], &smac[5]);
    // DMac broadcast
    memset(dmac, 0xff, 6);
    inet_pton(AF_INET, target_ip.c_str(), &dip);
    inet_pton(AF_INET, src_ip.c_str(), &sip);

    libnet_autobuild_ethernet(dmac, ETHERTYPE_ARP, l);
    libnet_build_arp(ARPHRD_ETHER, ETHERTYPE_IP, 6, 4,
                     ARPOP_REQUEST, smac, &sip, dmac, &dip,
                     nullptr, 0, l);

    int bytes = libnet_write(l);
    if (bytes == -1) {
        std::cerr << "libnet_write failed: " << libnet_geterror(l) << std::endl;
    }
    libnet_destroy(l);
}
src/SnmpSender.cpp

Код: Выделить всё

#include "SnmpSender.h"
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <iostream>

void SnmpSender::sendTrap(const std::string& message) {
    init_snmp("arp_monitor");
    snmp_session session;
    snmp_sess_init(&session);
    session.peername = strdup("localhost");
    session.community = (u_char*)strdup("public");
    session.community_len = strlen((char*)session.community);
    session.version = SNMP_VERSION_2c;

    snmp_session *ss = snmp_open(&session);
    if (!ss) {
        snmp_perror("snmp_open");
        return;
    }

    oid trap_oid[] = {1,3,6,1,6,3,1,1,5,1};
    netsnmp_variable_list *vars = nullptr;
    netsnmp_pdu *pdu = snmp_pdu_create(SNMP_MSG_TRAP2);
    snmp_add_var(pdu, snmp_oid_append(nullptr, trap_oid, sizeof(trap_oid)/sizeof(oid)), sizeof(trap_oid)/sizeof(oid), 's', message.c_str());

    if (!snmp_send(ss, pdu)) {
        snmp_perror("snmp_send");
    } else {
        std::cout << "SNMP Trap sent: " << message << std::endl;
    }

    snmp_close(ss);
}
src/ArpMonitor.cpp

Код: Выделить всё

#include "ArpMonitor.h"
#include <pcap.h>
#include <thread>
#include <iostream>
#include <cstring>
#include <netinet/ether.h>
#include <arpa/inet.h>
#include "ArpTable.h"
#include "ArpPacketFactory.h"
#include "SnmpSender.h"

ArpMonitor::ArpMonitor(const std::string& iface) : iface_(iface) {}

void ArpMonitor::addListener(std::shared_ptr<EventListener> listener) {
    listeners_.push_back(listener);
}

void ArpMonitor::start() {
    running_ = true;
    monitor_thread_ = std::thread(&ArpMonitor::monitorLoop, this);
}

void ArpMonitor::stop() {
    running_ = false;
    if (monitor_thread_.joinable()) {
        monitor_thread_.join();
    }
}

void ArpMonitor::monitorLoop() {
    char errbuf[PCAP_ERRBUF_SIZE];
    pcap_t *handle = pcap_open_live(iface_.c_str(), 65536, 1, 1000, errbuf);
    if (!handle) {
        std::cerr << "pcap_open_live failed: " << errbuf << std::endl;
        return;
    }

    struct bpf_program fp;
    if (pcap_compile(handle, &fp, "arp", 0, PCAP_NETMASK_UNKNOWN) == -1) {
        std::cerr << "pcap_compile failed" << std::endl;
        pcap_close(handle);
        return;
    }
    pcap_setfilter(handle, &fp);

    while (running_) {
        pcap_dispatch(handle, -1, [](u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) {
            auto *monitor = (ArpMonitor*)user;
            monitor->handlePacket(bytes, h->len);
        }, (u_char*)this);
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    pcap_close(handle);
}

void ArpMonitor::handlePacket(const u_char *packet, int length) {
    auto *eth = (struct ether_header*)packet;
    if (ntohs(eth->ether_type) != ETHERTYPE_ARP) return;

    auto *arp = (struct ether_arp*)(packet + sizeof(struct ether_header));
    char sender_ip[INET_ADDRSTRLEN];
    inet_ntop(AF_INET, arp->arp_spa, sender_ip, INET_ADDRSTRLEN);
    char sender_mac[18];
    snprintf(sender_mac, sizeof(sender_mac), "%02x:%02x:%02x:%02x:%02x:%02x",
             arp->arp_sha[0], arp->arp_sha[1], arp->arp_sha[2],
             arp->arp_sha[3], arp->arp_sha[4], arp->arp_sha[5]);

    std::string ip_str(sender_ip);
    std::string mac_str(sender_mac);

    try {
        ArpTable::getInstance().update(ip_str, mac_str);
        std::cout << "Device: " << ip_str << " MAC: " << mac_str << std::endl;
    } catch (const std::exception& e) {
        std::cerr << e.what() << std::endl;
        for (auto &listener : listeners_) {
            listener->onSuspiciousARP(ip_str, mac_str);
        }
    }
}
src/ArpMonitor.h

Код: Выделить всё

#ifndef ARP_MONITOR_H
#define ARP_MONITOR_H

#include "EventListener.h"
#include <string>
#include <thread>
#include <vector>
#include <memory>

class ArpMonitor {
private:
    std::string iface_;
    std::vector<std::shared_ptr<EventListener>> listeners_;
    std::thread monitor_thread_;
    std::atomic<bool> running_{false};

    void monitorLoop();

public:
    explicit ArpMonitor(const std::string& iface);
    void start();
    void stop();
    void addListener(std::shared_ptr<EventListener> listener);
};

#endif // ARP_MONITOR_H
main.cpp

Код: Выделить всё

#include "ArpMonitor.h"
#include "EventListener.h"
#include "SnmpSender.h"
#include "ArpPacketFactory.h"

#include <thread>
#include <chrono>
#include <vector>
#include <memory>
#include <iostream>

class AlertService : public EventListener {
public:
    void onSuspiciousARP(const std::string& ip, const std::string& mac) override {
        std::string msg = "Suspicious ARP detected for IP " + ip + " MAC " + mac;
        SnmpSender::sendTrap(msg);
    }
};

int main() {
    std::string iface = "eth0"; // замените на ваш интерфейс
    auto monitor = std::make_shared<ArpMonitor>(iface);
    auto alert_service = std::make_shared<AlertService>();
    monitor->addListener(alert_service);

    monitor->start();

    // Автоматический сканинг
    std::thread scanner([&iface]() {
        std::string local_ip = "192.168.1.100"; // замените на ваш IP
        std::string local_mac = "00:11:22:33:44:55"; // замените на ваш MAC
        std::vector<std::string> ip_range;
        for (int i = 1; i <= 254; ++i) {
            ip_range.push_back("192.168.1." + std::to_string(i));
        }
        while (true) {
            for (const auto& ip : ip_range) {
                ArpPacketFactory::sendArpRequest(ip, local_mac, local_ip, iface);
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
            }
            std::this_thread::sleep_for(std::chrono::minutes(5));
        }
    });

    // Запуск
    std::cout << "ARP monitor running. Press Enter to exit.\n";
    std::cin.get();

    monitor->stop();
    if (scanner.joinable()) scanner.join();

    return 0;
}
Makefile для сборки

Код: Выделить всё

CXX = g++
CXXFLAGS = -std=c++17 -Wall -Wextra
LIBS = -lpcap -llibnet -lnetsnmp

TARGET = arp_monitor

SRCDIR = src
INCDIR = include

SOURCES = $(wildcard $(SRCDIR)/*.cpp)
HEADERS = $(wildcard $(INCDIR)/*.h)
OBJECTS = $(SOURCES:.cpp=.o)

all: $(TARGET)

$(TARGET): $(OBJECTS)
    $(CXX) -o $@ $^ $(LIBS)

%.o: %.cpp $(HEADERS)
    $(CXX) -c -o $@ $< $(CXXFLAGS)

clean:
    rm -f $(TARGET) $(OBJECTS)

CMakeLists.txt

Код: Выделить всё

cmake_minimum_required(VERSION 3.10)
project(arp_monitor)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Указать исполняемый файл
add_executable(arp_monitor
    src/main.cpp
    src/ArpMonitor.cpp
    src/ArpPacketFactory.cpp
    src/SnmpSender.cpp
)

# Включить директории заголовочных файлов
target_include_directories(arp_monitor PRIVATE
    include
)

# Найти библиотеки libpcap, libnet, и net-snmp
find_package(Pcap REQUIRED)
find_package(LibNet REQUIRED)
find_package(NetSNMP REQUIRED)

# Связывать библиотеки
target_link_libraries(arp_monitor PRIVATE
    ${PCAP_LIBRARIES}
    ${LIBNET_LIBRARIES}
    ${NETSNMP_LIBRARIES}
)

# Включить необходимые директории (если нужны)
target_include_directories(arp_monitor PRIVATE
    ${PCAP_INCLUDE_DIRS}
    ${LIBNET_INCLUDE_DIRS}
    ${NETSNMP_INCLUDE_DIRS}
)

# Для автоматической загрузки пакетов
include(FindPkgConfig)
pkg_check_modules(PCAP REQUIRED libpcap)
pkg_check_modules(LIBNET REQUIRED libnet)
pkg_check_modules(NETSNMP REQUIRED net-snmp)

# Указать директории include для pkg-config
target_include_directories(arp_monitor PRIVATE
    ${PCAP_INCLUDE_DIRS}
    ${LIBNET_INCLUDE_DIRS}
    ${NETSNMP_INCLUDE_DIRS}
)

# Связывать с pkg-config
target_link_libraries(arp_monitor PRIVATE
    ${PCAP_LIBRARIES}
    ${LIBNET_LIBRARIES}
    ${NETSNMP_LIBRARIES}
)

# Обеспечить включение флагов
target_compile_options(arp_monitor PRIVATE
    ${PCAP_CFLAGS_OTHER}
    ${LIBNET_CFLAGS_OTHER}
    ${NETSNMP_CFLAGS_OTHER}
)

Код: Выделить всё

mkdir build
cd build
cmake ..
make
./arp_monitor

Re: пример расширенного ARP-сервера на с++ (сборка)

Добавлено: 06 дек 2025, 22:24
ya
Сборка статической линковки:

Код: Выделить всё

sudo apt update
sudo apt install libpcap-dev libnet-dev libsnmp-dev cmake build-essential
CMakeLists.txt

Код: Выделить всё

cmake_minimum_required(VERSION 3.10)
project(arp_monitor)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Включение статической линковки
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")

# Указание исходных файлов
add_executable(arp_monitor
    src/main.cpp
    src/ArpMonitor.cpp
    src/ArpPacketFactory.cpp
    src/SnmpSender.cpp
)

# Включение директории с заголовками
target_include_directories(arp_monitor PRIVATE
    include
)

# Обнаружение библиотек с помощью pkg-config
find_package(PkgConfig REQUIRED)

# Поиск libpcap
pkg_check_modules(PCAP REQUIRED libpcap)
# Поиск libnet
pkg_check_modules(LIBNET REQUIRED libnet)
# Поиск net-snmp
pkg_check_modules(NETSNMP REQUIRED libnet-snmp)

# Включение путей поиска заголовков
target_include_directories(arp_monitor PRIVATE
    ${PCAP_INCLUDE_DIRS}
    ${LIBNET_INCLUDE_DIRS}
    ${NETSNMP_INCLUDE_DIRS}
)

# Связывание библиотек
target_link_libraries(arp_monitor PRIVATE
    ${PCAP_LIBRARIES}
    ${LIBNET_LIBRARIES}
    ${NETSNMP_LIBRARIES}
)

# Включение флагов компиляции
target_compile_options(arp_monitor PRIVATE
    ${PCAP_CFLAGS_OTHER}
    ${LIBNET_CFLAGS_OTHER}
    ${NETSNMP_CFLAGS_OTHER}
)

Код: Выделить всё

mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make
./arp_monitor
Статическая линковка с системными библиотеками (-static) может привести к увеличению размера бинарника и иногда вызывает проблемы, особенно с libc. В этом случае можно убрать флаг или настроить его только для конкретных библиотек.
Для полной статической сборки рекомендуется использовать musl или специально собранные статические библиотеки, что усложняет процесс. На системах типа Devuan проще оставить динамическую линковку или использовать -static с осторожностью.