[NETFILTER]: Call NAT helper modules directly from conntrack modules, fixup FTP
Currently connection tracking and NAT helper modules for a protocol interact only indirectly (the conntrack module places information in the conntrack structure, which the NAT module pulls out). This leads to several issues: 1) Both modules must know what port to watch, and must match. 2) Identifying the particular packet which created the connection is cumbersome (TCP) or impossible (UDP). 3) The connection tracking code sets up an expectation which the NAT code then has to change. 4) The lack of direct symbol dependencies means we have to contrive one, since they are functionally dependent. Here is the current code flow: FTP CONTROL PACKET: NF_IP_PRE_ROUTING: ip_conntrack_in resolve_normal_ct init_conntrack: sets ct->helper to ip_conntrack_ftp.c:help() ct->help(): if PORT/PASV command: Sets exp->help.exp_ftp_info to tcp seq number of data. ip_conntrack_expect(): expects the connection ip_nat_setup_info: sets ct->nat.info->helper to ip_nat_ftp.c:help() ip_nat_fn: proto->exp_matches_pkt: if packet matches expectation ct->nat.info->helper(): If packet going client->server, and packet data is one in ct_ftp_info: ftp_data_fixup(): ip_conntrack_change_expect(): change the expectation Modify packet contents with new address. NF_IP_POST_ROUTING: ip_nat_fn ct->nat.info->helper(): If packet going server->client, and packet data is one in ct_ftp_info: ftp_data_fixup(): ip_conntrack_change_expect(): change the expectation Modify packet contents with new address. FTP DATA (EXPECTED) CONNECTION FIRST PACKET: NF_IP_PRE_ROUTING: ip_conntrack_in resolve_normal_ct init_conntrack: set ct->master. ip_nat_fn: master->nat.info.helper->expect() Set up source NAT mapping to match FTP control connection. NF_IP_PRE_ROUTING: ip_nat_fn: master->nat.info.helper->expect() Set up dest NAT mapping to match FTP control connection. The new flow looks like this: FTP CONTROL PACKET: NF_IP_PRE_ROUTING: ip_conntrack_in resolve_normal_ct init_conntrack: sets ct->helper to ip_conntrack_ftp.c:help() NF_IP_POST_ROUTING: ip_confirm: ct->helper->help: If !ip_nat_ftp_hook: ip_conntrack_expect(). ip_nat_ftp: set exp->oldproto to old port. ip_conntrack_change_expect(): change the expectation set exp->expectfn to ftp_nat_expected. Modify packet contents with new address. FTP DATA (EXPECTED) CONNECTION FIRST PACKET: NF_IP_PRE_ROUTING: ip_conntrack_in resolve_normal_ct init_conntrack: set ct->master. call exp->expectfn (ftp_nat_expected): call ip_nat_follow_master(). The big changes are that the ip_nat_ftp module sets ip_conntrack_ftp's ip_nat_ftp_hook when it initializes, so it calls the NAT code directly when a packet containing the expect information is found by the conntrack helper: and this interface can carry all the information these two want to share. Also, that conntrack helper is called as the packet leaves the box, so there are no issues with expectations being set up before the packet has been filtered. The NAT helper doesn't need to register and duplicate the conntrack ports. The other trick is ip_nat_follow_master(), which does the NAT setup all at once (source and destination NAT as required) such that the expected connection is NATed the same way the master connection was. We also call ip_conntrack_tcp_update() (which I incidentally neatened) after mangling a TCP packet; ip_nat_seq_adjust() does this, but now mangling is done at the last possible moment, after ip_nat_seq_adjust() was already called. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing
Please register or sign in to comment