From owner-freebsd-net@FreeBSD.ORG Mon Nov 29 10:09:53 2004 Return-Path: Delivered-To: freebsd-net@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id A89DE16A4CE for ; Mon, 29 Nov 2004 10:09:53 +0000 (GMT) Received: from amsfep18-int.chello.nl (amsfep18-int.chello.nl [213.46.243.13]) by mx1.FreeBSD.org (Postfix) with ESMTP id D042943D46 for ; Mon, 29 Nov 2004 10:09:52 +0000 (GMT) (envelope-from joost@jodocus.org) Received: from bps.jodocus.org ([80.57.157.16]) by amsfep18-int.chello.nl (InterMail vM.6.01.03.04 201-2131-111-106-20040729) with ESMTP id <20041129100950.BSXM7692.amsfep18-int.chello.nl@bps.jodocus.org>; Mon, 29 Nov 2004 11:09:50 +0100 Received: from jodocus.org (localhost [127.0.0.1]) by bps.jodocus.org (8.13.1/8.13.1) with ESMTP id iATA9oAB019585; Mon, 29 Nov 2004 11:09:50 +0100 (CET) (envelope-from joost@jodocus.org) Received: (from joost@localhost) by jodocus.org (8.13.1/8.13.1/Submit) id iATA9nWx019584; Mon, 29 Nov 2004 11:09:49 +0100 (CET) (envelope-from joost) Date: Mon, 29 Nov 2004 11:09:49 +0100 From: Joost Bekkers To: freebsd-net@freebsd.org Message-ID: <20041129100949.GA19560@bps.jodocus.org> Mail-Followup-To: Joost Bekkers , freebsd-net@freebsd.org, Ari Suutari Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="CE+1k2dSO48ffgeK" Content-Disposition: inline User-Agent: Mutt/1.4.2.1i Subject: (review request) ipfw and ipsec processing order for outgoing packets X-BeenThere: freebsd-net@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Networking and TCP/IP with FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 29 Nov 2004 10:09:53 -0000 --CE+1k2dSO48ffgeK Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hi A while ago there was a discussion about passing packet through pfil before they are processed by ipsec. I've posted a rough patch back then and I've finally had time to polish it. Although the changes seem very invasive at first glance, the .o files created are identical as long as IPSEC_FILTERGIF is not defined. With FAST_IPSEC diff(1) will tell you otherwise, but that is due to changed linenumbers which are used as arguments in two places. I've checked for differences by disassembling (objdump -d) the .o files. The attached patch is against 5.3R I'm running it myself with FAST_IPSEC. The combination of this patch and the kame ipsec could do with some more testing. -- greetz Joost joost@jodocus.org --CE+1k2dSO48ffgeK Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="ipsec_filtergif.diff" *** sys/netinet/dist/ip_output.c Sat Nov 27 20:56:56 2004 --- sys/netinet/ip_output.c Mon Nov 29 10:59:48 2004 *************** *** 405,410 **** --- 405,515 ---- } sendit: + + /* Ok, some really weird wizardry going on here. The goal is to pass + * packets that are going to be ipsec encapsulated pass through the + * firewall first. + * + * The PFIL code is split into two pieces: + * 1) the main part, which calls the pfil hooks and cleans up after them + * 2) a part that handles forwarding (if option IPFIREWALL_FORWARD is in the config) + * + * Because part 2 is not always include the #defines are done in two steps. + * + * There are five possible scenarios for this piece of code: + * + * 1) no ipsec at all -> pfil + * 2) Kame IPSEC without IPSEC_FILTERGIF -> ipsec, pfil + * 3) Kame IPSEC with IPSEC_FILTERGIF -> pfil, ipsec, pfil + * 4) FAST_IPSEC without IPSEC_FILTERGIF -> ipsec, pfil + * 5) FAST_IPSEC with IPSEC_FILTERGIF -> pfil, ipsec + * + * The first pfil location is therefor only used if IPSEC_FILTERGIF is defined. + * The second location is used if IPSEC_FILTERGIF is not defined of FAST_IPSEC + * is not defined. + * + * The difference in the kame and fast scenarios is caused by fast reinserting + * the encapsulated package and 'goto done' where kame will change the current + * package to be the encapsulated one. This also causes the strange location of + * the first PFIL(); In case of Kame ipsec the code should only be executed if + * the packet is actually going to be ipsec-ed. We don't want one packet going + * through the firewall twice. + */ + + #define PFIL_RUN_HOOKS(PASSOUT) \ + /* Jump over all PFIL processing if hooks are not active. */ \ + if (inet_pfil_hook.ph_busy_count == -1) \ + goto PASSOUT; \ + \ + /* Run through list of hooks for output packets. */ \ + odst.s_addr = ip->ip_dst.s_addr; \ + error = pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_OUT, inp); \ + if (error != 0 || m == NULL) \ + goto done; \ + \ + ip = mtod(m, struct ip *); \ + \ + /* See if destination IP address was changed by packet filter. */ \ + if (odst.s_addr != ip->ip_dst.s_addr) { \ + m->m_flags |= M_SKIP_FIREWALL; \ + if (in_localip(ip->ip_dst)) { \ + m->m_flags |= M_FASTFWD_OURS; \ + if (m->m_pkthdr.rcvif == NULL) \ + m->m_pkthdr.rcvif = loif; \ + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { \ + m->m_pkthdr.csum_flags |= \ + CSUM_DATA_VALID | CSUM_PSEUDO_HDR; \ + m->m_pkthdr.csum_data = 0xffff; \ + } \ + m->m_pkthdr.csum_flags |= \ + CSUM_IP_CHECKED | CSUM_IP_VALID; \ + \ + error = netisr_queue(NETISR_IP, m); \ + goto done; \ + } else \ + goto again; \ + } + + #define PFIL_FORWARD \ + /* See if local, if yes, send it to netisr with IP_FASTFWD_OURS. */ \ + if (m->m_flags & M_FASTFWD_OURS) { \ + if (m->m_pkthdr.rcvif == NULL) \ + m->m_pkthdr.rcvif = loif; \ + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { \ + m->m_pkthdr.csum_flags |= \ + CSUM_DATA_VALID | CSUM_PSEUDO_HDR; \ + m->m_pkthdr.csum_data = 0xffff; \ + } \ + m->m_pkthdr.csum_flags |= \ + CSUM_IP_CHECKED | CSUM_IP_VALID; \ + \ + error = netisr_queue(NETISR_IP, m); \ + goto done; \ + } \ + /* Or forward to some other address? */ \ + fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); \ + if (fwd_tag) { \ + if (!in_localip(ip->ip_src) && !in_localaddr(ip->ip_dst)) { \ + dst = (struct sockaddr_in *)&ro->ro_dst; \ + bcopy((fwd_tag+1), dst, sizeof(struct sockaddr_in)); \ + m->m_flags |= M_SKIP_FIREWALL; \ + m_tag_delete(m, fwd_tag); \ + goto again; \ + } else { \ + m_tag_delete(m, fwd_tag); \ + /* Continue. */ \ + } \ + } + + #ifdef IPFIREWALL_FORWARD + #define PFIL(endlabel) PFIL_RUN_HOOKS(endlabel) \ + PFIL_FORWARD \ + endlabel: + #else + #define PFIL(endlabel) PFIL_RUN_HOOKS(endlabel) \ + endlabel: + #endif + #ifdef IPSEC /* get SP for this packet */ if (inp == NULL) *************** *** 447,452 **** --- 552,564 ---- default: printf("ip_output: Invalid policy found. %d\n", sp->policy); } + #endif + + #ifdef IPSEC_FILTERGIF + PFIL(passout1) + #endif + + #ifdef IPSEC { struct ipsec_output_state state; bzero(&state, sizeof(state)); *************** *** 654,725 **** spd_done: #endif /* FAST_IPSEC */ ! /* Jump over all PFIL processing if hooks are not active. */ ! if (inet_pfil_hook.ph_busy_count == -1) ! goto passout; ! ! /* Run through list of hooks for output packets. */ ! odst.s_addr = ip->ip_dst.s_addr; ! error = pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_OUT, inp); ! if (error != 0 || m == NULL) ! goto done; ! ! ip = mtod(m, struct ip *); ! ! /* See if destination IP address was changed by packet filter. */ ! if (odst.s_addr != ip->ip_dst.s_addr) { ! m->m_flags |= M_SKIP_FIREWALL; ! if (in_localip(ip->ip_dst)) { ! m->m_flags |= M_FASTFWD_OURS; ! if (m->m_pkthdr.rcvif == NULL) ! m->m_pkthdr.rcvif = loif; ! if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { ! m->m_pkthdr.csum_flags |= ! CSUM_DATA_VALID | CSUM_PSEUDO_HDR; ! m->m_pkthdr.csum_data = 0xffff; ! } ! m->m_pkthdr.csum_flags |= ! CSUM_IP_CHECKED | CSUM_IP_VALID; ! ! error = netisr_queue(NETISR_IP, m); ! goto done; ! } else ! goto again; ! } ! ! #ifdef IPFIREWALL_FORWARD ! /* See if local, if yes, send it to netisr with IP_FASTFWD_OURS. */ ! if (m->m_flags & M_FASTFWD_OURS) { ! if (m->m_pkthdr.rcvif == NULL) ! m->m_pkthdr.rcvif = loif; ! if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { ! m->m_pkthdr.csum_flags |= ! CSUM_DATA_VALID | CSUM_PSEUDO_HDR; ! m->m_pkthdr.csum_data = 0xffff; ! } ! m->m_pkthdr.csum_flags |= ! CSUM_IP_CHECKED | CSUM_IP_VALID; ! ! error = netisr_queue(NETISR_IP, m); ! goto done; ! } ! /* Or forward to some other address? */ ! fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); ! if (fwd_tag) { ! if (!in_localip(ip->ip_src) && !in_localaddr(ip->ip_dst)) { ! dst = (struct sockaddr_in *)&ro->ro_dst; ! bcopy((fwd_tag+1), dst, sizeof(struct sockaddr_in)); ! m->m_flags |= M_SKIP_FIREWALL; ! m_tag_delete(m, fwd_tag); ! goto again; ! } else { ! m_tag_delete(m, fwd_tag); ! /* Continue. */ ! } ! } #endif - passout: /* 127/8 must not appear on wire - RFC1122. */ if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET || (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) { --- 766,779 ---- spd_done: #endif /* FAST_IPSEC */ ! #if !defined FAST_IPSEC || !defined IPSEC_FILTERGIF ! PFIL(passout2) #endif + #undef PFIL + #undef PFIL_RUN_HOOKS + #undef PFIL_FORWARD + /* 127/8 must not appear on wire - RFC1122. */ if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET || (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) { --CE+1k2dSO48ffgeK--