#define alloc_netdev( sizeof_priv, name, setup )
#define alloc_netdev( sizeof_priv, name, name_assign_type, setup )
/* interface name assignment types (sysfs name_assign_type attribute) */ #define NET_NAME_UNKNOWN 0 /* unknown origin (not exposed to userspace) */ #define NET_NAME_ENUM 1 /* enumerated by kernel */ #define NET_NAME_PREDICTABLE 2 /* predictably named by the kernel */ #define NET_NAME_USER 3 /* provided by user-space */ #define NET_NAME_RENAMED 4 /* renamed by user-space */
struct net_device_ops { int (*ndo_init)(struct net_device *dev); void (*ndo_uninit)(struct net_device *dev); int (*ndo_open)(struct net_device *dev); int (*ndo_stop)(struct net_device *dev); netdev_tx_t (*ndo_start_xmit) (struct sk_buff *skb, struct net_device *dev); ... struct net_device_stats* (*ndo_get_stats)(struct net_device *dev); ... }
struct net_device { char name[ IFNAMSIZ ] ; ... unsigned long base_addr; /* device I/O address */ unsigned int irq; /* device IRQ number */ ... unsigned mtu; /* interface MTU value */ unsigned short type; /* interface hardware type */ ... struct net_device_stats stats; struct list_head dev_list; ... /* Interface address info. */ unsigned char perm_addr[ MAX_ADDR_LEN ]; /* permanent hw address */ unsigned char addr_len; /* hardware address length */ ... }
... #define ARPHRD_ETHER 1 /* Ethernet 10Mbps */ ... #define ARPHRD_ARCNET 7 /* ARCnet */ ... #define ARPHRD_IEEE1394 24 /* IEEE 1394 IPv4 - RFC 2734 */ ... #define ARPHRD_IEEE80211 801 /* IEEE 802.11 */
/* netdev_priv - access network device private data * Get network device private data */ static inline void *netdev_priv( const struct net_device *dev ) { return (char *)dev + ALIGN( sizeof( struct net_device ), NETDEV_ALIGN ); }
#include <linux/module.h> #include <linux/version.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/moduleparam.h> #include <net/arp.h> #define ERR(...) printk( KERN_ERR "! "__VA_ARGS__ ) #define LOG(...) printk( KERN_INFO "! "__VA_ARGS__ ) static char* link = "eth0"; // module_param( link, charp, 0 ); static char* ifname = "virt"; // module_param( ifname, charp, 0 ); static struct net_device *child = NULL; struct priv { struct net_device_stats stats; struct net_device *parent; }; static rx_handler_result_t handle_frame( struct sk_buff **pskb ) { struct sk_buff *skb = *pskb; if( child ) { struct priv *priv = netdev_priv( child ); priv->stats.rx_packets++; priv->stats.rx_bytes += skb->len; LOG( "rx: injecting frame from %s to %s", skb->dev->name, child->name ); skb->dev = child; return RX_HANDLER_ANOTHER; } return RX_HANDLER_PASS; } static int open( struct net_device *dev ) { netif_start_queue( dev ); LOG( "%s: device opened", dev->name ); return 0; } static int stop( struct net_device *dev ) { netif_stop_queue( dev ); LOG( "%s: device closed", dev->name ); return 0; } static netdev_tx_t start_xmit( struct sk_buff *skb, struct net_device *dev ) { struct priv *priv = netdev_priv( dev ); priv->stats.tx_packets++; priv->stats.tx_bytes += skb->len; if( priv->parent ) { skb->dev = priv->parent; skb->priority = 1; dev_queue_xmit( skb ); LOG( "tx: injecting frame from %s to %s", dev->name, skb->dev->name ); return 0; } return NETDEV_TX_OK; } static struct net_device_stats *get_stats( struct net_device *dev ) { return &( (struct priv*)netdev_priv( dev ) )->stats; } static struct net_device_ops crypto_net_device_ops = { .ndo_open = open, .ndo_stop = stop, .ndo_get_stats = get_stats, .ndo_start_xmit = start_xmit, }; static void setup( struct net_device *dev ) { int j; ether_setup( dev ); memset( netdev_priv(dev), 0, sizeof( struct priv ) ); dev->netdev_ops = &crypto_net_device_ops; for( j = 0; j < ETH_ALEN; ++j ) // fill in the MAC address with a phoney dev->dev_addr[ j ] = (char)j; } int __init init( void ) { int err = 0; struct priv *priv; char ifstr[ 40 ]; sprintf( ifstr, "%s%s", ifname, "%d" ); #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)) child = alloc_netdev( sizeof( struct priv ), ifstr, setup ); #else child = alloc_netdev( sizeof( struct priv ), ifstr, NET_NAME_UNKNOWN, setup ); #endif if( child == NULL ) { ERR( "%s: allocate error", THIS_MODULE->name ); return -ENOMEM; } priv = netdev_priv( child ); priv->parent = __dev_get_by_name( &init_net, link ); // parent interface if( !priv->parent ) { ERR( "%s: no such net: %s", THIS_MODULE->name, link ); err = -ENODEV; goto err; } if( priv->parent->type != ARPHRD_ETHER && priv->parent->type != ARPHRD_LOOPBACK ) { ERR( "%s: illegal net type", THIS_MODULE->name ); err = -EINVAL; goto err; } /* also, and clone its IP, MAC and other information */ memcpy( child->dev_addr, priv->parent->dev_addr, ETH_ALEN ); memcpy( child->broadcast, priv->parent->broadcast, ETH_ALEN ); if( ( err = dev_alloc_name( child, child->name ) ) ) { ERR( "%s: allocate name, error %i", THIS_MODULE->name, err ); err = -EIO; goto err; } register_netdev( child ); rtnl_lock(); netdev_rx_handler_register( priv->parent, &handle_frame, NULL ); rtnl_unlock(); LOG( "module %s loaded", THIS_MODULE->name ); LOG( "%s: create link %s", THIS_MODULE->name, child->name ); LOG( "%s: registered rx handler for %s", THIS_MODULE->name, priv->parent->name ); return 0; err: free_netdev( child ); return err; } void __exit exit( void ) { struct priv *priv = netdev_priv( child ); if( priv->parent ) { rtnl_lock(); netdev_rx_handler_unregister( priv->parent ); rtnl_unlock(); LOG( "unregister rx handler for %s\n", priv->parent->name ); } unregister_netdev( child ); free_netdev( child ); LOG( "module %s unloaded", THIS_MODULE->name ); } module_init( init ); module_exit( exit ); MODULE_AUTHOR( "Oleg Tsiliuric" ); MODULE_AUTHOR( "Nikita Dorokhin" ); MODULE_LICENSE( "GPL v2" ); MODULE_VERSION( "2.1" );
$ ip addr show dev p7p1 3: p7p1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 08:00:27:9e:02:02 brd ff:ff:ff:ff:ff:ff inet 192.168.56.101/24 brd 192.168.56.255 scope global p7p1 inet6 fe80::a00:27ff:fe9e:202/64 scope link valid_lft forever preferred_lft forever
$ sudo insmod virt2.ko link=p7p1 $ sudo ifconfig virt0 192.168.50.2 $ ifconfig virt0 virt0 Link encap:Ethernet HWaddr 08:00:27:9E:02:02 inet addr:192.168.50.2 Bcast:192.168.50.255 Mask:255.255.255.0 inet6 addr: fe80::a00:27ff:fe9e:202/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:27 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 b) TX bytes:5027 (4.9 KiB)
$ sudo ifconfig vboxnet0:1 192.168.50.1 $ ifconfig ... vboxnet0 Link encap:Ethernet HWaddr 0A:00:27:00:00:00 inet addr:192.168.56.1 Bcast:192.168.56.255 Mask:255.255.255.0 inet6 addr: fe80::800:27ff:fe00:0/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:223 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 b) TX bytes:36730 (35.8 KiB) vboxnet0:1 Link encap:Ethernet HWaddr 0A:00:27:00:00:00 inet addr:192.168.50.1 Bcast:192.168.50.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
$ ping 192.168.50.1 PING 192.168.50.1 (192.168.50.1) 56(84) bytes of data. 64 bytes from 192.168.50.1: icmp_req=1 ttl=64 time=0.371 ms 64 bytes from 192.168.50.1: icmp_req=2 ttl=64 time=0.210 ms 64 bytes from 192.168.50.1: icmp_req=3 ttl=64 time=0.184 ms 64 bytes from 192.168.50.1: icmp_req=4 ttl=64 time=0.242 ms ^C --- 192.168.50.1 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3001ms rtt min/avg/max/mdev = 0.184/0.251/0.371/0.074 ms $ sudo tcpdump -i virt0 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on virt0, link-type EN10MB (Ethernet), capture size 65535 bytes 00:13:02.228615 IP 192.168.50.1 > 192.168.50.2: ICMP echo request, id 5609, seq 1, length 64 00:13:02.228716 ARP, Request who-has 192.168.50.1 tell 192.168.50.2, length 28 00:13:02.228786 ARP, Reply 192.168.50.1 is-at 0a:00:27:00:00:00 (oui Unknown), length 46 00:13:02.228803 IP 192.168.50.2 > 192.168.50.1: ICMP echo reply, id 5609, seq 1, length 64 00:13:03.227996 IP 192.168.50.1 > 192.168.50.2: ICMP echo request, id 5609, seq 2, length 64 00:13:03.228059 IP 192.168.50.2 > 192.168.50.1: ICMP echo reply, id 5609, seq 2, length 64 00:13:04.228016 IP 192.168.50.1 > 192.168.50.2: ICMP echo request, id 5609, seq 3, length 64 ... 00:14:09.236014 ARP, Request who-has 192.168.50.2 tell 192.168.50.1, length 46 00:14:09.236052 ARP, Reply 192.168.50.2 is-at 08:00:27:9e:02:02 (oui Unknown), length 28 tcpdump: pcap_loop: The interface went down 16 packets captured 16 packets received by filter 0 packets dropped by kernel
$ ssh 192.168.50.2 Nasty PTR record "192.168.50.2" is set up for 192.168.50.2, ignoring olej@192.168.50.2's password: Last login: Tue Apr 3 10:21:28 2012 from 192.168.1.5 $ uname -a Linux fedora16vm.localdomain 3.3.0-8.fc16.i686 #1 SMP Thu Mar 29 18:33:55 UTC 2012 i686 i686 i386 GNU/Linux $ exit logout Connection to 192.168.50.2 closed. $
$ ping 192.168.50.2 PING 192.168.50.2 (192.168.50.2) 56(84) bytes of data. 64 bytes from 192.168.50.2: icmp_req=1 ttl=64 time=0.473 ms 64 bytes from 192.168.50.2: icmp_req=2 ttl=64 time=0.256 ms 64 bytes from 192.168.50.2: icmp_req=3 ttl=64 time=0.281 ms ^C --- 192.168.50.2 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 1999ms rtt min/avg/max/mdev = 0.256/0.336/0.473/0.099 ms $ ping 192.168.56.101 PING 192.168.56.101 (192.168.56.101) 56(84) bytes of data. 64 bytes from 192.168.56.101: icmp_req=1 ttl=64 time=2.63 ms 64 bytes from 192.168.56.101: icmp_req=2 ttl=64 time=0.306 ms 64 bytes from 192.168.56.101: icmp_req=3 ttl=64 time=0.225 ms ^C --- 192.168.56.101 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2002ms rtt min/avg/max/mdev = 0.225/1.053/2.630/1.115 ms $ dmesg | tail -n19 [58382.498200] virt0: no IPv6 routers present [58391.368273] device virt0 entered promiscuous mode [58409.904046] ! rx: IP4 to IP=192.168.50.2 [58409.904050] ! rx: injecting frame from p7p1 to virt0 [58409.904197] ! tx: injecting frame from virt0 to p7p1 [58409.904212] ! rx: ARP for 192.168.50.2 [58409.904214] ! rx: injecting frame from p7p1 to virt0 [58409.904262] ! tx: injecting frame from virt0 to p7p1 [58410.903427] ! rx: IP4 to IP=192.168.50.2 [58410.903431] ! rx: injecting frame from p7p1 to virt0 [58410.903531] ! tx: injecting frame from virt0 to p7p1 [58411.903447] ! rx: IP4 to IP=192.168.50.2 [58411.903451] ! rx: injecting frame from p7p1 to virt0 [58411.903547] ! tx: injecting frame from virt0 to p7p1 [58414.694485] ! rx: ARP for 192.168.56.101 [58414.696846] ! rx: IP4 to IP=192.168.56.101 [58415.696508] ! rx: IP4 to IP=192.168.56.101 [58416.696572] ! rx: IP4 to IP=192.168.56.101 [58419.712245] ! rx: ARP for 192.168.56.101
Source: https://habr.com/ru/post/269987/
All Articles