INNOVA, version 0.0.1 Claudio Agosti - vecna@s0ftpj.org - Sun Jan 11 18:32:54 CET 2004 innova is a software aiming to manipulate its own connections in a way which can't be found out by the application managing communication (client web, mail, etc). It uses a plugin system to define actions to be undertaken on connection. Main manipulations coming to my mind are: - ciphering - steganography - anti-IDS/anti-sniffing systems - traffic dumps/replays - pattern runtime changes within sessions - and on and on... It is usually necessary to work on kernel level to manipulate this way, by using modules hooking some function after ip_send (concerning Linux) but, for many reasons, programming in userspace is better. Managing raw sock within userspace troubles as it creates packets of connections not traced by kernel (as it happens with connect(2)), thus our kernel will answer the box we came in contact by using sock raw. So, it disconnect connection it didn't ask for. innova is a software which can manipulate connection from userspace without interfering with kernel and application work, through local diversion and filtering systems included in netfilter. If we want to modify packets in a seetrough way, we need to work after common tcp/ip stack. innova only acts within userspace: by taking advantage of some netfilter modules, it can manipulate packets before kernel processes them and even after kernel releases them (before net driver code). netfilter/iptables callings and networking setup are managed by innova framework. userspace | kernel | innova (userspace) --------------\ \---------------------------- \ \ BitchX --------> tcp ip \ innova reads and modifies packet in a \ \ transparent way lynx --------> tcp ip \ \ -------> bind --------> udp ip \ kernel keeps a trace of the session \ \ userspace application works on tftp --------> udp ip \ \ \ innova acts before reading and after --------------\---------------\ sending by kernel. On its own, innova doesn't manipulate anything, it's a framework managing traffic seetrough diversion system by offering a set of functions which can be called a shared object working as a plugin. You can find a list of plugins included into packet (and the ones which will be added one by one, we gladly accept any contributions :) on the site http://www.s0ftpj.org/projects/innova . Coming into details: to redirect, innova executes the following operations (this list could seem a long, wrong, ugly one, but it's the only one that can solve the problem: simpler options could have problems): As for incoming packets, which are not being read by kernel before innova does: 1) A DROP rule is added to block selected packets (innova should accept as command line argument or through plugins some information about host/netmask, protocol or port in order to be able to distinguish within traffic. Packets innova has to read are to be dropped for kernel. This is for the ones specified in "filter", INPUT chain table, NOT the ones whose TTL is 255. 2) A socket to datalink layer (binded by feature packet(7)) analyzing each packet received is held. Everytime it finds a packet matching innova requirements (so, a one already dropped) it passes that to plugin (there's a specific function for remotely read packets and another one for locally read packets). 3) Packets are sent back to localhost with TTL equal to 255 (so that they won't match anymore drop rule and they'll be accepted by kernel). (This will be improved in the future, as soon as target ROUTE will be added to kernel stable) As for outgoing packets, which are being accepted by innova after application has passed data to send and after kernel has adapted them to connection: 1) An iptables rule is added to output chain, mangle table (that's the first among all outgoing packets hooks to be called and analyzed by netfilter framework) in order to mark (through -j MARK) every packet coming from innova pid. Match extension related to packets owner is necessary. 2) An iptables rule is added to output chain, filter table having -j ULOG target. It forwards to netlink device (netlink(7) and netlink(3)) every packet is to be passed to innova (otherwise, if innova sent packets having same discriminants as the ones matched by this rule, it would origin a loop). 3) On output chain, in the last table (the nat one) a MASQUERADING rule is applied to all packets, except for the ones coming from innova pid. In fact, netlink, as the second rule states, doesn't delete packets, it just copies them (LOG and ULOG don't interfere with normal packets vital cycle, as man page explains). By appling MASQUERADING rule they are not forwarded. This is necessary since wrapped applications packets must not outgo; though, it is also true I can't use a simple -j DROP, as that target returns -EPERM to system call creating packet if the latter is created by local host. This can cause problems for all softwares checking return values of their sendto/connect, ecc... Then packets couldn't be dropped immediately, and the problem has been solved by diverting them to localhost. MASQUERADE target is necessary to recompute routing rule, added through iproute, and policies. 4) A routing table is created, so that packets marked by the first rule are discriminated. It is thus necessary to validate within kernel [*] IP: advanced router [*] IP: policy routing [*] IP: use netfilter MARK value as routing key and to have iproute suite installed. Netfilter needing modules, instead, is related to: IP table support (required for filtering/masq/NAT) netfilter MARK match support TTL match support Owner match support (EXPERIMENTAL) Full NAT MASQUEREADE target support Packet mangling MARK target support ULOG target support Though the route followed by packets could seem complicated, at present I haven't better solutions allowing me to do the same (I suggest you to read in netlink.c rules generation function). Anyway, I'm sure innova will be improved by target ROUTE and /dev/netfiltes_ipv4 support to match packets within userspace (so that it will be possible to discriminate through layer 5 and more...). Anyway, innova will be soon supplied with a kernel module, depending on netfilter, that will act as the iptables calls, and will thus allow that to be cleaner and more performing. innova has 3 useful structures, that you need to know if you want to code plugins, if you are just interested in how it runs I suggest you to read README.example . innova_struct: it describes how framework at that moment works and opened file descriptors. It also has a void pointer named "foo", which can be used as user wants, in advantage of plugin. innova_options: it contains referrings to options applied to innova. These are data describing remote host, service, protocol or any extension, they place pointer to foo_options_f function at user disposal and even "foo" pointer, which can be used if plugin programmer wants to. innova_packet: it describes packet going through innova. It is provided with a function pointer which is executed before sending (after mangle functions). innova framework running has the following order: 1) Options reading 2) Network initialization 3) Plugins initialization Plugins API, that are functions in which a plugin should intercept selected packets and process them according to its code, are: char *(* get_io_desc)(int *); It returns a buffer pointer containing plugin name or description. It is only necessary to write launched plugin name. Int pointer, instead, is necessary to have a value assigned by module, so that it can communicate PLUGIN_FORMAT value; this value is necessary to keep modules versions trace and to check whether they have been compiled or not for innova version running them. int (* mangle_opt_parse)(v_innova_struct_p, v_innova_options_p); is called before net initializing. It is usually employed to analyze options passed to plugin (the ones shown by innova -o switch, and then divided into argc and argv in advantage of analysis or to use getopt within this function). Since it is called before any initialization, it is possible to change all innova_struct and innova_options parameters, without depending on innova common running or options passed by user. As plugin needs to be able to completely control operations executed by innova, this function can give access to a lot of data. int (* mangle_init)(v_innova_struct_p); This function is called after initializing network. It is necessary to initialize plugin and it can be called again depending on mangle_cleanup function return value. It accepts as arguments innova_struct function; we assume data it needs are included either into innova_struct or into innova_options (or rather have been parsed by mangle_opt_parse and are kept within plugin). If mangle_opt_parse can be used as plugin initializer, this is the initializer of each session which can be managed by innova. int (* mangle_cleanup)(v_innova_struct_p, int); mangle_cleanup receives innova_struct and error code that generated cleanup function call: depending either on this value or on plugin, mangle_cleanup return code can force innova to execute again and again mangle_init... or it can lead program to exit. If mangle_init can be considered as the initialization of a single session managed through innova, mangle_cleanup will manage its closing. int (* local_mangle)(v_innova_struct_p, v_innova_packet_p); local_mangle is a function analyzing local packets matching rules set by innova. It accepts as arguments innova_struct and innova_packet; depending on return value (if it is < 0 it's an error, otherwise it goes on), innova execution will go on and packet will be forwarded towards remote host (depending on what plugin asks innova to do). int (* remote_mangle)(v_innova_struct_p, v_innova_packet_p); As for remote_mangle, it's the same, it's a call for packets received from remote. int (* io_timeexceed)(v_innova_struct_p, int *); Function io_timeexceed is called when system call select(2) timeout expires because it doesn't receive any packet to be processed according to innova rules either from inside or from outside. This function can be used within keepalive situations, timeout is resetted everytime a packet arrives. (README.en translated by Tanith )