430 likes | 736 Views
CS 498 Lecture 13 Inside Netfilter. Jennifer Hou Department of Computer Science University of Illinois at Urbana-Champaign Reading: Oskar Andreasson, Iptables Tutorial , http://iptables-tutorial.frozentux.net/
E N D
CS 498 Lecture 13 Inside Netfilter Jennifer Hou Department of Computer Science University of Illinois at Urbana-Champaign Reading: Oskar Andreasson, Iptables Tutorial, http://iptables-tutorial.frozentux.net/ Rusty Russell and Harald Welta, Netfilter Hacking Howto , http://www.netfilter.org/documentation/index.html
Internet Protocol Implementation in Linux Higher Layers ip_input.c ip_output.c ip_queue_xmit ip_local_deliver MULTICAST IP_LOCAL_OUTPUT . . . ip_mr_input IP_LOCAL_INPUT ip_queue_xmit2 ip_forward.c IP_FORWARD ip_local_deliver ip_forward_finish ip_forward ip_output ip_fragment ip_finish_output ip_rcv_finish ROUTING ForwardingInformation Base IP_POST_ROUTING IP_PRE_ROUTING ip_route_input ip_rcv ip_finish_output2 ARP ARP neigh_resolve_output dev.c dev.c dev_queue_xmit net_rx_action
Data Structures in Netfilter Defined in include/linux/netfilter_ipv4/ip_tables.h
Data Structure - Table • struct ipt_table (ip_tables.h) • Is a linked list to store all tables • Defines a table, e.g., 'nat','filter','mangle' • Contains a struct ipt_table_info that stores the firewall rules in entries • A table is registerd using ipt_register_table (in init_module()) and unregistered by ipt_unregister_table (in cleanup_module())
How Data Structures are Organized ipt_entry next target ipt_entry next target ipt_entry next target ipt_table_info entries ipt_table private ipt_entry next target ipt_entry next target ipt_entry next target ipt_entry next target ipt_entry next target
Data Structure - Entry • struct ipt_entry contains • A struct ipt_ip that contains the specification for the IP header that it is to match • An nfcache bitfield that gives what parts of the packet the rule exams. • A target_offset field that indicates the offset where the ipt_entry_target structure begins. • A next_offset field that indicates the total size of this rule. • A comefrom field that keeps track of packet traversal. • A struct ipt_counter field that contains the packet/byte counters for packets that matched this rule. • struct ipt_entry stores a variable number of ipt_entry_match after ipt_entry, and an ipt_entry_target after matches
The ipt_entry Struct ipt_entry target_offset next_offset elems ipt_entry target_offset next_offset elems ipt_entry_match match data ipt_entry_match match data One or more matches ipt_entry_match match data ipt_entry_match match data ipt_entry_target target data ipt_entry_target target data
Data Structure - Match • struct ipt_entry_match • u.kernel.match : a pointer to a struct ipt_match • data : the user-defined matchinfo • struct ipt_match • list is set to {NULL,NULL} • name: the name of the match function, as referred to by userspace • match is a pointer to the match function; returns true if the packet matches • If hotdrop is set to 1 and the return value is zero, the packet should be dropped immediately. • checkentry is a pointer to a function that checks the specifications for a rule. If the function returns 0, the rule will not be accepted from the user. • A user-defined match is registered by ipt_register_match and unregistered by ipt_unregister_match
Data Structure - Target • struct ipt_entry_target • u.kernel.target : a pointer to struct ipt_target • data : user-defined targetinfo • struct ipt_target • list is set to {NULL,NULL} • name: the name of the match function, as referred to by userspace • target is a pointer to the target function • takes the skb buffer, the hook number, the input and output device pointers, a pointer to the target area, and the position of the rule in the table. • Returns IPT_CONTINUE to continue traversing, or a verdict (NF_DROP, NF_ACCEPT, NF_STOLEN, etc)
Data Structure - Target • struct ipt_target (cont’d) • checkentry is a pointer to a function that checks the specifications for a rule; if the function returns 0, then the rule will not be accepted from the user. • A user-defined target is registered by ipt_register_target and unregistered by ipt_unregister_target
Hooks • NF_HOOK(int pf, unsigned int hook, struct sk_buff *skb, struct net_device *indev, struct net_device *outdev, int (*okfn)(struct sk_buff *) • Defined as a macro NF_HOOK(pf, hook, skb, indev, outdev, okfn) \ (list_empty(&nf_hooks[(pf)][(hook)]) ? (okfn)(skb): \ nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn), INT_MIN)) • Invoked in, for exmaple, ip_local_ deliver() in net/ipv4/ip_input.c: return NF_HOOK(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL, ip_local_deliver_finish);
nf_hook_ops struct nf_hook_ops { struct list_head list; /* User fills in from here down. */ nf_hookfn *hook; struct module *owner; int pf; int hooknum; /* Hooks are ordered in ascending priority. */ int priority; }; Hooks are registered by calling nf_register_hook in the module_init functions
Netfilter Hook Implementation Step 1 • To implement a network filter, fill out the nf_hook_ops structure static struct nf_hook_ops simple_ops = { { NULL, NULL }, simple_hook, PF_INET, NF_IP_LOCAL_OUT, NF_IP_PRI_FILTER-1 };
Netfilter Hook Implementation Step 2 • Write the hook function static unsigned int simple_hook(unsigned int hook, struct sk_buff **pskb, const struct net_device *indev, const struct net_device *outdev, int (*okfn)(struct sk_buff *)) { /* Get a handle to the packet data */ unsigned char *data = (void *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl*4; (*pskb)->nfcache |= NFC_UNKNOWN; switch ((*pskb)->len) { case 100: printk("linuxmag: corrupting packet\n"); data[99]++; (*pskb)->nfcache |= NFC_ALTERED; return NF_ACCEPT; case 200: printk("linuxmag: dropping packet\n"); return NF_DROP; default: return NF_ACCEPT; } }
Netfilter Hook Implementation Step 3 • Register the network filter with nf_register_hook() #include <linux/config.h> #include <linux/module.h> #include <linux/netfilter_ipv4.h> #include <linux/ip.h> Following this comes the simple_hook function, then the simple_ops structure, then static int __init init(void) { return nf_register_hook(&linuxmag_ops); } static void __exit fini(void) { nf_unregister_hook(&linuxmag_ops); } module_init(init); module_exit(fini);
From IP Stack to Hooks NF_HOOK( NF_IP_PRE_ROUTING ) NF_HOOK( NF_IP_LOCAL_IN ) NF_HOOK( NF_IP_FORWARD ) NF_HOOK( NF_IP_POST_ROUTING ) NF_HOOK( NF_IP_LOCAL_OUT ) nf_hook_slow() elem = &nf_hooks[pf][hook] verdict = nf_iterate(...,&elem,...) nf_iterate() for each elem in list elem->hook(...) ipt_do_table(.., table,.. ) traverse the entries of table if match do target
ipt_do_table ipt_do_table() e = get_entry(...) back = get_entry(...) do { if( ip_packet_match(...) ) { if( IPT_MATCH_ITERATE(...) !=0) goto no_match t = ipt_get_target(e) if( t is standard target) v = t->verdict if( v == IPT_RETURN) e=back; back=... if( v < 0 ) verdict = (-v)-1 break else e=get_entry(...,v) else v = t->target(...) } } while(!hotdrop)
A Generic Hook • ipt_do_table in ip_tables.c • Do generic ip packet check (ip_packet_match) • Iterate through all the matches of an entry in a given table • If the packet matches, call the target of the entry • If the verdict returned from the target function is IPT_RETURN, go back to the entry where we came from • If IPT_CONTINUE, go to the next entry
Implementing a Netfilter Match • In the iptables framework • Under iptables/extensions/, place the libipt_xxx.c program, where xxx is the name of the match. • Add xxx in iptables/extensions/Makefile • The shared library, libipt_xxx.c, should have an _init() function, which will automatically be called upon loading. • The moral equivalent of the kernel module is init_module() function. • The _init() function should call register_match() with a pointer to an iptables_match entry as the argument.
Data Structure in iptables.h struct iptables_match { struct iptables_match *next; ipt_chainlabel name; const char *version; /* Size of match data. */ size_t size; /* Size of match data relevent for userspace comparison purposes */ size_t userspacesize; /* Function which prints out usage message. */ void (*help)(void); /* Initialize the match. */ void (*init)(struct ipt_entry_match *m, unsigned int *nfcache); /* Function which parses command options; returns true if it ate an option */ int (*parse)(int c, char **argv, int invert, unsigned int *flags, const struct ipt_entry *entry, unsigned int *nfcache, struct ipt_entry_match **match); Set to IPTABLES_VERSION Use IPT_ALIGN(0 macro to ensure it is correctly aligned Used to initialize the extra space (if any) in ipt_entry_match structure and set nfcache bits
Data Structure in iptables.h /* Final check; exit if not ok. */ void (*final_check)(unsigned int flags); /* Prints out the match iff non-NULL: put space at end */ void (*print)(const struct ipt_ip *ip, const struct ipt_entry_match *match, int numeric); /* Saves the match info in parsable form to stdout. */ void (*save)(const struct ipt_ip *ip, const struct ipt_entry_match *match); /* Pointer to list of extra command-line options */ const struct option *extra_opts; } Used by the chain listing code to print the match information
In libipt_xxx.c • Define the iptables_match structure static struct iptables_match ipaddr = { .name = "ipaddr", .version = IPTABLES_VERSION, .size = IPT_ALIGN(sizeof(struct ipt_ipaddr_info)), .userspacesize = IPT_ALIGN(sizeof(struct ipt_ipaddr_info)), .help = &help, .init = &init, .parse = &parse, .final_check = &final_check, .print = &print, .save = &save, .extra_opts = opts }; • Register the match in the _init() function. void _init(void) { register_match(&ipaddr); }
Implementing a Netfilter Match • In the netfilter framework • Under linux/net/ipv4/netfilter, place the ipt_xxx.c kernel module • Under linux/include/linux/netfilter_ipv4/, add ipt_xxx.h header file.
The Netfilter Kernel Module • See the handout for the match function • static struct ipt_match ipaddr_match = { .name = "ipaddr", .match = match, .checkentry = checkentry, .me = THIS_MODULE, }; • static int __init init(void) { printk(KERN_INFO "ipt_ipaddr: init!\n"); return ipt_register_match(&ipaddr_match); } static void __exit fini(void) { printk(KERN_INFO "ipt_ipaddr: exit!\n"); ipt_unregister_match(&ipaddr_match); } module_init(init); module_exit(fini);
The psd Match Module • Port scan detector • Doesn't come with the default netfilter code. Use patch-o-matic to add this module • Keep a hash table to store entries based on its source address. • If a packet destined to a different port arrives within the delay threshold, add lo_ports_weight (for port <1024) or hi_ports_weight to the total weight. • If the total weight exceeds weight_threshold, alerts a possible port scan. • The structure is similar to the port knocking module in project 5
The psd Match Module (cont.) • ipt_psd_match (ipt_psd.c) • L167: find this source address in the hash table • L177: if the entry is not too old, check if we have seen this port • L221: add this port • L286: add a new entry to the hash table
Port scanning • A method of probing a computer to see what ports are open. • A brute force operation • One simply tries to establish a connection to each and every port on the target computer. • When a connection is established, the caller makes note of the port number and continues on. • The caller can then examine these ports later to see if any known security holes exist.
Port Knocking • As long as ports remain open, network applications are susceptible to attack ports are initially closed. • A handful of ports are configured to deny all traffic – no ICMP error packets are sent back to the connecting client. • Users make connection attempts to sequence of closed ports. All failed connection attempts are logged by the server-side packet filtering firewall and detected by a daemon that monitors the firewall log file. • When a properly formatted knock sequence is received, firewall rules are manipulated based on the information content of the sequence.
Example • Ports 100-109 are configured to deny all traffic. • ipchains -A input -p tcp -s 0/0 -d IPF/32 100:109 -j DENY -l • A user attempts to connect from IPC to the following firewall ports in sequence: 102,100,100,103. • From the point of view of the user, the connections fail silently. • On the firewall, the 102,100,100,103 number sequence has been recorded. • Feb 12 00:13:26 ... input DENY eth1 PROTO=6 IPC:64137 IPF:102 ... • Feb 12 00:13:27 ... input DENY eth1 PROTO=6 IPC:64138 IPF:100 ... • Feb 12 00:13:27 ... input DENY eth1 PROTO=6 IPC:64139 IPF:100 ... • Feb 12 00:13:28 ... input DENY eth1 PROTO=6 IPC:64140 IPF:103 ... • The knock sequence appears in the firewall log.
Implementation • A method is needed to monitor the firewall log file. • A method is required to extract the sequence of ports from the log file and translate them into usable information. • How to detect a port sequence begins and ends. • How to correctly detect a port sequence in the presence of spurious connection attempts that are not part of the sequence.
Example of Implementation • Ports 100-109 are used to listen to knocks. • The port sequence is expected to be of the form: 102,100,110 10a,10b,10c,10d 10(a+b+c+d mod 10) 110,100,102 header payload checksum footer • The first and last three ports let the port knocking dæmon know that a sequence is starting and ending. • The next four ports encode the port (abcd) to be opened. • For example, if a connection to port 143 is required, the sequence would be 100,101,104,103. • The final element in the sequence is a checksum that validates the sequence payload. • In this example, the checksum is 8 (1+4+3 mod 10). • The full sequence would be 102,100,103 100,101,104,103 108 103,100,102.
Example of Implementation • When this sequence is detected, port 143 would be made available to the incoming IP address. • If the port is open already, the knock would rendered it closed. • The knock can be extended to include additional information, such as an anticipated session length, that can be used to close the port after a set amount of time.
Mapping with Encryption • The information contained in the knock sequence can be encrypted to provide an additional measure of security. • Example: • 256 ports are allocated and logged. • A knock map of the form remote IP port time checksum is used where the remote IP, port, time and checksum (sum of other fields mod 255) are encrypted. • The encrypted string can be mapped onto eight unsigned chars using, for example, Perl's pack("C*",STRING) command.
Benefits • Port knocking provides a stealthy method of authentication and information transfer to a host that has no open ports. • It is not possible to determine successfully whether the machine is listening for knock sequences. • It is unlikely that the form of connection attempts would be detected by monitoring traffic. • A sequence can corresponds to a request that a port be opened for a specific length of time and then closed.
Disadvantages • Performance penality: use of port knocking imposes an overhead for each connection. • A number of ports have to be allocated for exclusive use by port knocking. • In the case that no ports are initially open, if the listening daemon fails or is not able to interpret the knocks correctly, it becomes impossible to conect remotely to the host.