3#include <linux/etherdevice.h>
6#include <linux/proc_fs.h>
7#include <linux/if_arp.h>
8#include <linux/if_ether.h>
26 pr_err(
"VNET: не удалось зарегистрировать sysctl-таблицу\n");
33 pr_err(
"VNET: не удалось выделить сетевое устройство\n");
50 pr_err(
"VNET: не удалось зарегистрировать сетевое устройство\n");
64 pr_err(
"VNET: не удалось поднять интерфейс %s (ошибка %d)\n",
vnet_dev->name, err);
65 pr_info(
"VNET: можно поднять интерфейс вручную: sudo ip link set %s up\n",
vnet_dev->name);
71 pr_info(
"VNET: интерфейс %s переведён в состояние UP\n",
vnet_dev->name);
76 pr_err(
"VNET: не удалось назначить IP %s на %s (ошибка %d)\n",
vnet_ip_str,
vnet_dev->name, err);
77 pr_warn(
"VNET: можно назначить IP вручную: sudo ip addr add %s/24 dev %s\n",
vnet_ip_str,
vnet_dev->name);
82 pr_info(
"VNET: модуль успешно инициализирован, MAC=%pM\n",
vnet_dev->dev_addr);
83 pr_info(
"VNET: изменить IP можно так: echo \"NEW_IP\" | sudo tee /proc/sys/net/vnet/ip_addr\n");
95 pr_info(
"VNET: освобождение sysctl-таблицы\n");
100 pr_info(
"VNET: модуль выгружен\n");
110static bool str_to_ip(__u32 *ip_out,
const char *ip_str, spinlock_t *lock) {
113 if (in4_pton(ip_str, -1, (u8 *) ip_out, -1, NULL) <= 0) {
114 spin_unlock_bh(lock);
117 spin_unlock_bh(lock);
131static netdev_tx_t
vnet_xmit(
struct sk_buff *skb,
struct net_device *dev) {
132 struct vnet_priv *priv = netdev_priv(dev);
144 priv->
stats.tx_dropped++;
150 if (skb->protocol == htons(ETH_P_ARP)) {
152 priv->
stats.rx_packets++;
153 priv->
stats.rx_bytes += skb->len;
159 if (skb->protocol == htons(ETH_P_IP)) {
161 skb_reset_network_header(skb);
163 struct iphdr *iph = ip_hdr(skb);
166 if (unlikely(skb->len <
sizeof(
struct iphdr))) {
167 priv->
stats.rx_length_errors++;
173 if (ip_fast_csum((u8 *) iph, iph->ihl) != 0) {
174 priv->
stats.rx_crc_errors++;
180 if (iph->protocol == IPPROTO_ICMP) {
182 if (unlikely(skb->len < iph->ihl * 4 +
sizeof(
struct icmphdr))) {
183 priv->
stats.rx_length_errors++;
189 skb_set_transport_header(skb, skb_network_offset(skb) + (
int) skb_network_header_len(skb));
191 const struct icmphdr *icmph = icmp_hdr(skb);
194 if (icmph->type == ICMP_ECHO && iph->daddr == target_ip) {
195 struct sk_buff *new_skb = skb_copy(skb, GFP_ATOMIC);
198 struct iphdr *new_iph = ip_hdr(new_skb);
199 struct icmphdr *new_icmph = icmp_hdr(new_skb);
202 const __u32 tmp = new_iph->saddr;
203 new_iph->saddr = new_iph->daddr;
204 new_iph->daddr = tmp;
208 new_iph->check = ip_fast_csum((u8 *) new_iph, new_iph->ihl);
211 new_icmph->type = ICMP_ECHOREPLY;
214 new_icmph->checksum = 0;
215 new_icmph->checksum = ip_compute_csum((
unsigned char *) new_icmph,
216 ntohs(new_iph->tot_len) - new_iph->ihl * 4);
220 new_skb->protocol = eth_type_trans(new_skb, dev);
223 priv->
stats.tx_packets++;
224 priv->
stats.tx_bytes += new_skb->len;
226 if (netif_rx(new_skb) == NET_RX_SUCCESS) {
227 priv->
stats.rx_packets++;
228 priv->
stats.rx_bytes += new_skb->len;
237 priv->
stats.tx_errors++;
245 priv->
stats.tx_dropped++;
256 struct vnet_priv const *priv = netdev_priv(dev);
266static void vnet_arp_reply(
struct sk_buff
const *skb,
struct net_device *dev, __u32 target_ip) {
268 unsigned char const *arp_ptr;
269 unsigned char const *sha;
270 unsigned char const *tha;
273 struct sk_buff *reply_skb;
277 if (arp->ar_op != htons(ARPOP_REQUEST))
281 arp_ptr = (
unsigned char *) (arp + 1);
283 arp_ptr += dev->addr_len;
284 memcpy(&sip, arp_ptr, 4);
287 arp_ptr += dev->addr_len;
288 memcpy(&tip, arp_ptr, 4);
291 if (tip != target_ip)
295 reply_skb = arp_create(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, dev->dev_addr, sha);
298 pr_err(
"VNET: не удалось сформировать ARP reply\n");
304 struct vnet_priv *priv = netdev_priv(dev);
305 priv->
stats.tx_packets++;
306 priv->
stats.tx_bytes += skb->len;
318static int vnet_sysctl_handler(
const struct ctl_table *table,
int write,
void *buffer,
size_t *lenp, loff_t *ppos) {
325 ret = proc_dostring(table, write, buffer, lenp, ppos);
327 pr_err(
"VNET: ошибка обработки sysctl-запроса\n");
338 pr_err(
"VNET: неверный формат IP-адреса: %s\n",
vnet_ip_str);
343 pr_info(
"VNET: IP изменён: %s -> %s\n", old_ip,
vnet_ip_str);
348 pr_err(
"VNET: не удалось удалить старый IP-адрес %s (ошибка %d)\n", old_ip, ret);
352 pr_info(
"VNET: старый IP-адрес удалён: %s\n", old_ip);
357 pr_err(
"VNET: не удалось добавить новый IP-адрес %s (ошибка %d)\n",
vnet_ip_str, ret);
362 pr_info(
"VNET: IP-адрес интерфейса обновлён до %s\n",
vnet_ip_str);
381 if (!name || !ip_str)
386 snprintf(cmd,
sizeof(cmd),
"/sbin/ip addr add %s/24 dev %s 2>/dev/null", ip_str, name);
388 snprintf(cmd,
sizeof(cmd),
"/sbin/ip addr del %s/24 dev %s 2>/dev/null", ip_str, name);
391 argv[i++] =
"/bin/sh";
396 pr_info(
"VNET: выполнение команды: %s\n", cmd);
399 return call_usermodehelper(argv[0], argv, NULL, UMH_WAIT_PROC);
Приватные данные интерфейса vnet.
struct rtnl_link_stats64 stats
static void vnet_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
Возвращает статистику интерфейса для ndo_get_stats64.
MODULE_DESCRIPTION("Virtual Net Interface")
static void vnet_arp_reply(struct sk_buff const *skb, struct net_device *dev, __u32 target_ip)
Формирует и отправляет ARP reply.
static int __init virtual_net_init(void)
Инициализирует модуль: sysctl, интерфейс и стартовый IP.
module_init(virtual_net_init)
static netdev_tx_t vnet_xmit(struct sk_buff *skb, struct net_device *dev)
Обрабатывает skb интерфейса и эмулирует ответное сетевое поведение.
static void __exit virtual_net_exit(void)
Освобождает ресурсы модуля при выгрузке.
module_exit(virtual_net_exit)
static bool str_to_ip(__u32 *ip_out, const char *ip_str, spinlock_t *lock)
Преобразует IPv4 строку в 32-битный адрес в network byte order.
static int modify_vif_ip_userspace(const char *name, const char *ip_str, bool is_add)
Изменяет IPv4 адрес интерфейса через userspace-команду ip.
static int vnet_sysctl_handler(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos)
Обработчик sysctl для /proc/sys/net/vnet/ip_addr.
MODULE_AUTHOR("Dmitry Chernikov")
Общие определения для модуля виртуального сетевого интерфейса.
static const struct net_device_ops vnet_ops
Операции сетевого устройства vnet.
static struct ctl_table vnet_table[]
Таблица sysctl для /proc/sys/net/vnet/ip_addr.
#define VNET_IFNAME
Имя создаваемого виртуального интерфейса.
static struct net_device * vnet_dev
Указатель на зарегистрированное сетевое устройство vnet.
static struct ctl_table_header * vnet_sysctl_header
Дескриптор Зарегистрированной таблицы sysctl.
static char vnet_ip_str[16]
Текущее значение IPv4 адреса интерфейса в строковом виде.