Copyright (C) 2007 Université Paris 13 Written by Luca Saiu This patch is released under the GNU General Public License v2 or any later version published by the Free Software Foundation, Inc. See the added comments in the patch for information about who wrote what. Ghostification support ====================== This project consists in a small kernel patch allowing the user to "ghostify" one or several network interfaces. The patch is against Linux 2.6.18. What ghostification means ------------------------- A network interface in "ghostified" state continues to operate as usual and can be normally employed by user applications for communication. Sockets can be opened and closed and packets are normally sent, received and routed. However a ghostified interface is different from a non-ghostified network interface in the following respects: * Its presence can not be detected by user processes: kernel ioctl's don't report the interface presence, and when they receive its name as parameter they fail as if the interface didn't exist, with -ENODEV. The /proc virtual filesystem doesn't contain references to its name. * Its configuration can't be *queried* by user processes: the kernel answers with an error when receiving any configuration query ioctl. Routes involving a ghostified interface are not shown to user processes, although they continue to be normally followed by the kernel. * Its configuration can't be *changed* by user processes: the network interface can't be disabled if currently enabled, or vice-versa. Its address (at all levels, from network down to hardware) can't be changed. Routes involving it cannot be added or removed. * Packets received by a ghostified interface are never copied to AF_PACKET sockets, so that user-level sniffers don't see any traffic when reading from a generic AF_PACKET socket associated to "all" network interfaces. * A ghostified interface can be "unghostified" (see below), after which its state reverts to normal. The implementation has been heavily tested only on Ethernet, loopback, bridge and TUN/TAP devices, but is expected to work on any other kind of network interface. The code is architecture-idependent, SMP-safe and also works in User Mode Linux. User interface -------------- A normal network interface can be ghostified and a ghostified one can be "unghostified" with the new SIOCGIFGHOSTIFY and SIOCGIFUNGHOSTIFY ioctls. Both take the interface name as parameter and return 0 on success or a negative error code on failure, according to ioctl conventions. On ghostification and unghostification some lines are written to the system log, explaining what happened in an understandable way and listing the currently ghostified network interfaces. Two simple user-level programs "ghostify" and "unghostify" are provided for convenience: they take the interface name as their only command line parameter. A third command line parameter "klog" and its associated SIOKLOG ioctl serve the single purpose of writing to the system log, and may be useful for debugging. They aren't meant to be employed for production and can be safely ignored by the user. Limitations ----------- The current implementation imposes a fixed limit to the number of network interface which can be in ghostified state in any given moment. The limit is currently set to 8, but can be trivially raised by modifying the MAX_GHOST_INTERFACES_NO macro in net/core/dev.c . The implementation was tested on a network using IPv4 and IPv6. Some operations in more exoteric protocols might not be correctly filtered, and in particular the interface name could show up somewhere under /proc if such protocols were employed. Implementation -------------- The implementation is failry simple and unobtrusive. Its bulk resides in net/core/dev.c, where a simple fixed-length array of fixed-length strings is defined, ghost_interface_names. Such structure is static and always accessed from the outside via is_a_ghost_interface_name() -- which makes changing the implementation fairly easy, should it ever be needed. Structure updates are performed only from within net/core/dev.c, which also contains what essentially is the full implementation of the new ioctls in ghostify_interface() and unghostify_interface(). Their common table lookup functionality is implemented in __lookup_ghost_interface_names(). Such functions (and their unlocked counterparts, where appliable) are of course all static. The data structure initialization is performed in netdev_boot_setup(), in net/core/dev.c . Critical sections are implemented with a spinlock (ghost_interface_spin_lock), and the only exported function, is_a_ghost_interface_name(), is reentrant. The behaviour of several ioctls has been modified according to the specification above, including all SIOCxIFxxx calls (see net/core/dev.c), and SIOCDELRT and SIOCADDRT (see net/ipv4/fib_frontend.c, net/ipv4/fib_trie.c, net/ipv4/fib_hash.c, net/ipv6/route.c). Many modifications just consist in the addition of a call to is_a_ghost_interface_name() within a conditional, making an operation fail when a ghostified interface is involved. Such updates pertain to many files under net/ . Similar modifications have the purpose of "filtering out" some lines displayed in files under /proc/ . A slightly more involved modification consists in making a file under /proc/net/dev_snmp6/ appear or disapper at ghostification or unghostification time. The implementation is in net/ipv6/addrconf.c and net/ipv6/proc.c . Sockets with address format AF_PACKET are dealt with in net/packet/af_packet.c . Modifications just consist in selective packet dropping, even if in several distinct cases. Multicast and memory-mapped devices are explicitly supported. The user-space utilities ghostify, unghostify and klog are written by reusing large part of the source code for the ifconfig program from the net-tools package. Their core consists in a simple ioctl invocation. Implementation rationale ------------------------ The cleanest, most straightforward and also most efficient way of keeping track of which interface is currently ghostified would have been adding a new field to struct net_device, defined in include/linux/netdevice.h . Unfortunately such structure is exported to the user level, and even just appending a field to its end would have changed its size, breaking binary compatibility with user applications. We decided to fall back to a less efficient solution, which shouldn't however cause perceivable slowdowns because of the extremely small size of our fixed table. Even using a hash table would have probably been overkill for such a small structure, and could actually have resulted in higher access time. is_a_ghost_interface_name() has constant complexity, consisting (in the worst case) in MAX_GHOST_INTERFACES_NO string comparisons where all strings have size less than IFNAMSIZ (currently defined as 16 in in include/linux/if.h). Using a unique index (such as the ifindex field of struct net_device) instead of the interface name would have probably been less efficient, as many kernel structures and interfaces work with interface names expressed as strings. Contact information ------------------- For any bug report or comment, the author is reachable at the address [To do: should we make a mailing list?]. License ------- This patch is released under the GNU GPL v2 or later.