[Openswan dev] mangled packets, ESP on mast0, after ip_select_ident() fix

Paul Wouters paul at xelerance.com
Tue Jul 19 10:10:37 EDT 2011


On Tue, 19 Jul 2011, David McCullough wrote:

> Jivin Paul Wouters lays it down ...
>>
>> I've tracked down the recent issues with protostack=mast, and found that the
>> following commit seems to have badly broken the mast stack:

> I'm a bit confused,  does the patch below fix something to do with the
> change above ?  They seem completely unrelated to me.  If thats the only
> change needed to fix it then go for it ;-)

Oops, that was not the entire patch. It was the diff after reverting, so
the full undo action was this:


diff --git a/linux/include/openswan/ipsec_xmit.h b/linux/include/openswan/ipsec_xmit.h
index ccee7ce..09e2a17 100644
--- a/linux/include/openswan/ipsec_xmit.h
+++ b/linux/include/openswan/ipsec_xmit.h
@@ -135,7 +135,6 @@ struct ipsec_xmit_state
  	 * xmit flags
  	 */
  	uint16_t mast_mode:1;
-	uint16_t set_dst:1;

  	/* if carrying IPv6,  IPPROTO_IPV6, else IPPROTO_IPIP */
  	uint8_t ipip_proto;
@@ -185,8 +184,11 @@ extern atomic_t ipsec_ixs_cnt;

  extern void ipsec_extract_ports(struct sk_buff *skb, unsigned char nexthdr, int nexthdroff, struct sockaddr_encap * er);

+/* avoid forward reference complain on < 2.5 */
+struct flowi;
+
  extern enum ipsec_xmit_value
-ipsec_xmit_send(struct ipsec_xmit_state *ixs);
+ipsec_xmit_send(struct ipsec_xmit_state*ixs, struct flowi *fl);

  extern enum ipsec_xmit_value
  ipsec_nat_encap(struct ipsec_xmit_state*ixs);
diff --git a/linux/net/ipsec/ipsec_mast.c b/linux/net/ipsec/ipsec_mast.c
index 7d5596f..c49f7c3 100644
--- a/linux/net/ipsec/ipsec_mast.c
+++ b/linux/net/ipsec/ipsec_mast.c
@@ -278,7 +278,17 @@ ipsec_mast_xsm_complete(
  	}
  #endif

-	ipsec_xmit_send(ixs);
+#ifdef NETDEV_25	/* 2.6 kernels */
+	/* now send the packet again */
+	{
+		struct flowi fl;
+ 
+		memset(&fl, 0, sizeof(fl));
+		ipsec_xmit_send(ixs, &fl);
+	}
+#else
+	ipsec_xmit_send(ixs, NULL);
+#endif

  cleanup:
  	ipsec_xmit_cleanup(ixs);
diff --git a/linux/net/ipsec/ipsec_xmit.c b/linux/net/ipsec/ipsec_xmit.c
index 4fbb1bb..3408a7a 100644
--- a/linux/net/ipsec/ipsec_xmit.c
+++ b/linux/net/ipsec/ipsec_xmit.c
@@ -109,8 +109,6 @@ static __u32 zeroes[64];
  #endif
  #endif

-static int ipsec_set_dst(struct ipsec_xmit_state *ixs);
-
  int ipsec_xmit_trap_count = 0;
  int ipsec_xmit_trap_sendcount = 0;

@@ -1181,7 +1179,6 @@ ipsec_xmit_ah(struct ipsec_xmit_state *ixs)
  enum ipsec_xmit_value
  ipsec_xmit_ipip(struct ipsec_xmit_state *ixs)
  {
-	int error;
  #ifdef CONFIG_KLIPS_IPV6
  	if (ip_address_family(&ixs->ipsp->ips_said.dst) == AF_INET6) {
  		ixs->skb->ip_summed = CHECKSUM_NONE;
@@ -1196,9 +1193,6 @@ ipsec_xmit_ipip(struct ipsec_xmit_state *ixs)
  		osw_ip6_hdr(ixs)->saddr    = ((struct sockaddr_in6*)(ixs->ipsp->ips_addr_s))->sin6_addr;
  		osw_ip6_hdr(ixs)->daddr    = ((struct sockaddr_in6*)(ixs->ipsp->ips_addr_d))->sin6_addr;
  		osw_ip6_hdr(ixs)->nexthdr  = ixs->ipip_proto;
-		error = ipsec_set_dst(ixs);
-		if (error != IPSEC_XMIT_OK)
-			return error;
  		/* DAVIDM No identification/fragment code here yet */
  		skb_set_transport_header(ixs->skb, ipsec_skb_offset(ixs->skb, ixs->iph));
  	} else
@@ -1225,11 +1219,9 @@ ipsec_xmit_ipip(struct ipsec_xmit_state *ixs)
  		osw_ip4_hdr(ixs)->daddr    = ((struct sockaddr_in*)(ixs->ipsp->ips_addr_d))->sin_addr.s_addr;
  		osw_ip4_hdr(ixs)->protocol = ixs->ipip_proto;
  		osw_ip4_hdr(ixs)->ihl      = sizeof(struct iphdr) >> 2;
+
  		/* newer kernels require skb->dst to be set in KLIPS_IP_SELECT_IDENT */
  		/* we need to do this before any HASH generation is done */
-		error = ipsec_set_dst(ixs);
-		if (error != IPSEC_XMIT_OK)
-			return error;
  		KLIPS_IP_SELECT_IDENT(osw_ip4_hdr(ixs), ixs->skb);
  #ifdef NET_21
  		skb_set_transport_header(ixs->skb, ipsec_skb_offset(ixs->skb, ixs->iph));
@@ -2509,64 +2501,61 @@ enum ipsec_xmit_value ipsec_nat_encap(struct ipsec_xmit_state *ixs)
  #endif


-static int ipsec_set_dst(struct ipsec_xmit_state *ixs)
+/* avoid forward reference complain on <2.5 */
+struct flowi;
+
+enum ipsec_xmit_value
+ipsec_xmit_send(struct ipsec_xmit_state*ixs, struct flowi *fl)
  {
+	int error;
+	int is_mast_packet;
  	struct dst_entry *dst = NULL;
-	int error = 0;
-#ifdef NETDEV_25
-	struct flowi fl;
-#endif

-	if (ixs->set_dst)
-		return IPSEC_XMIT_OK;
+	/* check if this packet is sent from the mast, before we route */
+	is_mast_packet = ipsec_is_mast_device(ixs->skb->dev);

  #ifdef NETDEV_25
-	memset(&fl, 0, sizeof(fl));
-
-	/* new route/dst cache code from James Morris */
-	ixs->skb->dev = ixs->physdev;
-	fl.flowi_oif = ixs->physdev ? ixs->physdev->ifindex : 0;

  #ifdef CONFIG_KLIPS_IPV6
-	if (osw_ip_hdr_version(ixs) == 6) {
+	if (ip_hdr(ixs->skb)->version == 6) {
  		if (ixs->pass)
-			memset(&fl.nl_u.ip6_u.saddr, 0, sizeof(fl.nl_u.ip6_u.saddr));
+			memset(&fl->nl_u.ip6_u.saddr, 0, sizeof(fl->nl_u.ip6_u.saddr));
  		else
-			fl.nl_u.ip6_u.saddr = osw_ip6_hdr(ixs)->saddr;
-		fl.nl_u.ip6_u.daddr = osw_ip6_hdr(ixs)->daddr;
-		/* fl->nl_u.ip6_u.tos = RT_TOS(osw_ip6_hdr(ixs)->tos); */
-		fl.flowi_proto = IPPROTO_IPV6;
+			fl->nl_u.ip6_u.saddr = ipv6_hdr(ixs->skb)->saddr;
+		fl->nl_u.ip6_u.daddr = ipv6_hdr(ixs->skb)->daddr;
+		/* fl->nl_u.ip6_u.tos = RT_TOS(ipv6_hdr(ixs->skb)->tos); */
+		fl->flowi_proto = IPPROTO_IPV6;
  #ifndef FLOW_HAS_NO_MARK
-		fl.flowi_mark = ixs->skb->mark;
+		fl->flowi_mark = ixs->skb->mark;
  #endif
  #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)
-		dst = ip6_route_output(NULL, &fl);
+		dst = ip6_route_output(NULL, fl);
  #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39)
-		dst = ip6_route_output(&init_net, NULL, &fl);
+		dst = ip6_route_output(&init_net, NULL, fl);
  #else
-		dst = ip6_route_output(&init_net, NULL, &fl.nl_u.ip6_u);
+		dst = ip6_route_output(&init_net, NULL, fl->nl_u.ip6_u);
  #endif
  		error = dst->error;
  	} else
  #endif /* CONFIG_KLIPS_IPV6 */
  	{
-		fl.nl_u.ip4_u.daddr = osw_ip4_hdr(ixs)->daddr;
-		fl.nl_u.ip4_u.saddr = ixs->pass ? 0 : osw_ip4_hdr(ixs)->saddr;
-		fl.flowi_tos = RT_TOS(osw_ip4_hdr(ixs)->tos);
-		fl.flowi_proto = osw_ip4_hdr(ixs)->protocol;
+               fl->nl_u.ip4_u.daddr = ip_hdr(ixs->skb)->daddr;
+               fl->nl_u.ip4_u.saddr = ixs->pass ? 0 : ip_hdr(ixs->skb)->saddr;
+               fl->flowi_tos = RT_TOS(ip_hdr(ixs->skb)->tos);
+               fl->flowi_proto = ip_hdr(ixs->skb)->protocol;
  #ifndef FLOW_HAS_NO_MARK
-		fl.flowi_mark = ixs->skb->mark;
+		fl->flowi_mark = ixs->skb->mark;
  #endif
  #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39)
  # if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)
-		error = ip_route_output_key(&ixs->route, &fl);
+		error = ip_route_output_key(&ixs->route, fl);
  # else
-		error = ip_route_output_key(&init_net, &ixs->route, &fl);
+		error = ip_route_output_key(&init_net, &ixs->route, fl);
  # endif
  		if (ixs->route)
  			dst = &ipsec_route_dst(ixs->route);
  #else
-		ixs->route = ip_route_output_key(&init_net, &fl.u.ip4);
+		ixs->route = ip_route_output_key(&init_net, &fl->u.ip4);
  		if (IS_ERR(ixs->route)) {
  			error = PTR_ERR(ixs->route);
  			ixs->route = NULL;
@@ -2582,9 +2571,9 @@ static int ipsec_set_dst(struct ipsec_xmit_state *ixs)
  #endif
  	/*skb_orphan(ixs->skb);*/
  	error = ip_route_output(&ixs->route,
-				    osw_ip4_hdr(ixs)->daddr,
-				    ixs->pass ? 0 : osw_ip4_hdr(ixs)->saddr,
-				    RT_TOS(osw_ip4_hdr(ixs)->tos),
+				    ip_hdr(ixs->skb)->daddr,
+				    ixs->pass ? 0 : ip_hdr(ixs->skb)->saddr,
+				    RT_TOS(ip_hdr(ixs->skb)->tos),
                                      /* mcr->rgb: should this be 0 instead? */
  				    ixs->physdev->ifindex);
  	if (ixs->route)
@@ -2615,7 +2604,7 @@ static int ipsec_set_dst(struct ipsec_xmit_state *ixs)
  		ixs->skb->dev = dst->dev;

  	if(ixs->dev == dst->dev) {
-		if (osw_ip_hdr_version(ixs) == 6)
+		if (ip_hdr(ixs->skb)->version == 6)
  			dst_release(dst);
  		else
  			ip_rt_put(ixs->route);
@@ -2632,33 +2621,6 @@ static int ipsec_set_dst(struct ipsec_xmit_state *ixs)
  	skb_dst_drop(ixs->skb);
  	skb_dst_set(ixs->skb, dst);

-	ixs->set_dst = 1;
-
-	return IPSEC_XMIT_OK;
-}
-
-
-enum ipsec_xmit_value
-ipsec_xmit_send(struct ipsec_xmit_state *ixs)
-{
-	int error;
-	int is_mast_packet;
-
-	if (ixs->skb == NULL || ixs->skb->dev == NULL)
-		return IPSEC_XMIT_NODEV;
-
-	/* check if this packet is sent from the mast, before we route */
-	is_mast_packet = ipsec_is_mast_device(ixs->skb->dev);
-
-	/*
-	 * ipsec_set_dst may have been done in the IPIP code,  or we do it now.
-	 * DAVIDM - I actually think it must have always been done before
-	 *          now,  but ESP without IPIP and no AH may be the
-	 *          exception.  You cannot hash and then do ipsec_set_dst :-)
-	 */
-	error = ipsec_set_dst(ixs);
-	if (error != IPSEC_XMIT_OK)
-		return error;

  	if(ixs->stats) {
  		ixs->stats->tx_bytes += ixs->skb->len;
@@ -2735,11 +2697,26 @@ ipsec_xmit_send(struct ipsec_xmit_state *ixs)
  	return IPSEC_XMIT_OK;
  }

+#ifdef NETDEV_25
  enum ipsec_xmit_value
  ipsec_tunnel_send(struct ipsec_xmit_state *ixs)
  {
-	return ipsec_xmit_send(ixs);
+	struct flowi fl;
+	memset(&fl, 0, sizeof(fl));
+
+	/* new route/dst cache code from James Morris */
+	ixs->skb->dev = ixs->physdev;
+ 	fl.flowi_oif = ixs->physdev->ifindex;
+
+	return ipsec_xmit_send(ixs, &fl);
  }
+#else
+enum ipsec_xmit_value
+ipsec_tunnel_send(struct ipsec_xmit_state *ixs)
+{
+	return ipsec_xmit_send(ixs, NULL);
+}
+#endif


  /*


More information about the Dev mailing list