Skip to contentSkip to conversation

sctp: make IPSec rules effective with IPv6

PATCH In review Wei Yongjun 3 participants 5 messages Apr 20, 2010

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 sctp: make IPSec rules effective with IPv6

IPSec rules are ineffective with IPv6 transmit currently, so this patch make them effective with IPv6.
Idea from Nicolas Dichtel <[email protected]>

---
 include/net/sctp/structs.h |    3 +++
 net/sctp/ipv6.c            |   23 +++++++++++++++++++++++
 net/sctp/transport.c       |    3 +++
 3 files changed, 29 insertions(+), 0 deletions(-)
include/net/sctp/structs.h +3 -0
index ff30177..5fe4df4 100644
@@ -569,6 +569,9 @@ struct sctp_af {
 	struct dst_entry *(*get_dst)	(struct sctp_association *asoc,
 					 union sctp_addr *daddr,
 					 union sctp_addr *saddr);
+	struct dst_entry *(*get_xfrm_dst)(struct dst_entry **dst_p,
+					  union sctp_addr *daddr,
+					  union sctp_addr *saddr);
 	void		(*get_saddr)	(struct sctp_sock *sk,
 					 struct sctp_association *asoc,
 					 struct dst_entry *dst,
net/sctp/ipv6.c +23 -0
index 9fb5d37..09a4c9c 100644
@@ -271,6 +271,28 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
 	return NULL;
 }
 
+static struct dst_entry *sctp_v6_get_xfrm_dst(struct dst_entry **dst_p,
+					       union sctp_addr *daddr,
+					       union sctp_addr *saddr)
+{
+	struct flowi fl;
+
+	SCTP_DEBUG_PRINTK("%s: daddr:%pI6 saddr:%pI6",
+		__func__, &daddr->v6.sin6_addr, &saddr->v6.sin6_addr);
+
+	memset(&fl, 0, sizeof(fl));
+	fl.proto = IPPROTO_SCTP;
+	fl.fl_ip_dport = daddr->v6.sin6_port;
+	fl.fl_ip_sport = saddr->v6.sin6_port;
+	ipv6_addr_copy(&fl.fl6_dst, &daddr->v6.sin6_addr);
+	ipv6_addr_copy(&fl.fl6_src, &saddr->v6.sin6_addr);
+
+	if (xfrm_lookup(&init_net, dst_p, &fl, NULL, 0) < 0)
+		return NULL;
+	else
+		return *dst_p;
+}
+
 /* Returns the number of consecutive initial bits that match in the 2 ipv6
  * addresses.
  */
@@ -962,6 +984,7 @@ static struct sctp_af sctp_af_inet6 = {
 	.setsockopt	   = ipv6_setsockopt,
 	.getsockopt	   = ipv6_getsockopt,
 	.get_dst	   = sctp_v6_get_dst,
+	.get_xfrm_dst	   = sctp_v6_get_xfrm_dst,
 	.get_saddr	   = sctp_v6_get_saddr,
 	.copy_addrlist	   = sctp_v6_copy_addrlist,
 	.from_skb	   = sctp_v6_from_skb,
net/sctp/transport.c +3 -0
index be4d63d..f89dd4d 100644
@@ -298,6 +298,9 @@ void sctp_transport_route(struct sctp_transport *transport,
 	else
 		af->get_saddr(opt, asoc, dst, daddr, &transport->saddr);
 
+	if (af->get_xfrm_dst)
+		dst = af->get_xfrm_dst(&dst, daddr, &transport->saddr);
+
 	transport->dst = dst;
 	if ((transport->param_flags & SPP_PMTUD_DISABLE) && transport->pathmtu) {
 		return;
Signature · 1 line
1.6.5.2
#1 lore raw

What about the PMTU problem?

I've understand that this solution will not work:

You wrote:
"This would work for transmit SCTP packet under IPSEC, the problem is that we can not get the correct PMTU for the transport.Under IPv4, both transmit and the PMTU is correct."

Regards,
Nicolas

Quoted 80 lines · Wei Yongjun

IPSec rules are ineffective with IPv6 transmit currently, so this patch make them effective with IPv6.
Idea from Nicolas Dichtel <[email protected]>

---
 include/net/sctp/structs.h |    3 +++
 net/sctp/ipv6.c            |   23 +++++++++++++++++++++++
 net/sctp/transport.c       |    3 +++
 3 files changed, 29 insertions(+), 0 deletions(-)
include/net/sctp/structs.h +3 -0
index ff30177..5fe4df4 100644
@@ -569,6 +569,9 @@ struct sctp_af {
 	struct dst_entry *(*get_dst)	(struct sctp_association *asoc,
 					 union sctp_addr *daddr,
 					 union sctp_addr *saddr);
+	struct dst_entry *(*get_xfrm_dst)(struct dst_entry **dst_p,
+					  union sctp_addr *daddr,
+					  union sctp_addr *saddr);
 	void		(*get_saddr)	(struct sctp_sock *sk,
 					 struct sctp_association *asoc,
 					 struct dst_entry *dst,
net/sctp/ipv6.c +23 -0
index 9fb5d37..09a4c9c 100644
@@ -271,6 +271,28 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
 	return NULL;
 }
 
+static struct dst_entry *sctp_v6_get_xfrm_dst(struct dst_entry **dst_p,
+					       union sctp_addr *daddr,
+					       union sctp_addr *saddr)
+{
+	struct flowi fl;
+
+	SCTP_DEBUG_PRINTK("%s: daddr:%pI6 saddr:%pI6",
+		__func__, &daddr->v6.sin6_addr, &saddr->v6.sin6_addr);
+
+	memset(&fl, 0, sizeof(fl));
+	fl.proto = IPPROTO_SCTP;
+	fl.fl_ip_dport = daddr->v6.sin6_port;
+	fl.fl_ip_sport = saddr->v6.sin6_port;
+	ipv6_addr_copy(&fl.fl6_dst, &daddr->v6.sin6_addr);
+	ipv6_addr_copy(&fl.fl6_src, &saddr->v6.sin6_addr);
+
+	if (xfrm_lookup(&init_net, dst_p, &fl, NULL, 0) < 0)
+		return NULL;
+	else
+		return *dst_p;
+}
+
 /* Returns the number of consecutive initial bits that match in the 2 ipv6
  * addresses.
  */
@@ -962,6 +984,7 @@ static struct sctp_af sctp_af_inet6 = {
 	.setsockopt	   = ipv6_setsockopt,
 	.getsockopt	   = ipv6_getsockopt,
 	.get_dst	   = sctp_v6_get_dst,
+	.get_xfrm_dst	   = sctp_v6_get_xfrm_dst,
 	.get_saddr	   = sctp_v6_get_saddr,
 	.copy_addrlist	   = sctp_v6_copy_addrlist,
 	.from_skb	   = sctp_v6_from_skb,
net/sctp/transport.c +3 -0
index be4d63d..f89dd4d 100644
@@ -298,6 +298,9 @@ void sctp_transport_route(struct sctp_transport *transport,
 	else
 		af->get_saddr(opt, asoc, dst, daddr, &transport->saddr);
 
+	if (af->get_xfrm_dst)
+		dst = af->get_xfrm_dst(&dst, daddr, &transport->saddr);
+
 	transport->dst = dst;
 	if ((transport->param_flags & SPP_PMTUD_DISABLE) && transport->pathmtu) {
 		return;
#2 lore raw
In reply to Wei Yongjun
Quoted 10 lines

What about the PMTU problem?

I've understand that this solution will not work:

You wrote:
"This would work for transmit SCTP packet under IPSEC, the problem is that we can not get the correct PMTU for the transport.Under IPv4, both transmit and the PMTU is correct."

Yeah, sorry for that, the PMTU problem maybe because I did the wrong thing in the past when I do the same thing. And now when I try to solution it, but works :-( . I do not know whether this implementation has other problem.

Maybe we should do strict route select in sctp_v6_get_dst(), use the address from the asoc or the dev address, do the same thing as IPv4.

Quoted 88 lines

Regards,
Nicolas

Quoted 81 lines · Wei Yongjun

IPSec rules are ineffective with IPv6 transmit currently, so this patch make them effective with IPv6.
Idea from Nicolas Dichtel <[email protected]>

---
 include/net/sctp/structs.h |    3 +++
 net/sctp/ipv6.c            |   23 +++++++++++++++++++++++
 net/sctp/transport.c       |    3 +++
 3 files changed, 29 insertions(+), 0 deletions(-)
include/net/sctp/structs.h +3 -0
index ff30177..5fe4df4 100644
@@ -569,6 +569,9 @@ struct sctp_af {
 	struct dst_entry *(*get_dst)	(struct sctp_association *asoc,
 					 union sctp_addr *daddr,
 					 union sctp_addr *saddr);
+	struct dst_entry *(*get_xfrm_dst)(struct dst_entry **dst_p,
+					  union sctp_addr *daddr,
+					  union sctp_addr *saddr);
 	void		(*get_saddr)	(struct sctp_sock *sk,
 					 struct sctp_association *asoc,
 					 struct dst_entry *dst,
net/sctp/ipv6.c +23 -0
index 9fb5d37..09a4c9c 100644
@@ -271,6 +271,28 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
 	return NULL;
 }
 
+static struct dst_entry *sctp_v6_get_xfrm_dst(struct dst_entry **dst_p,
+					       union sctp_addr *daddr,
+					       union sctp_addr *saddr)
+{
+	struct flowi fl;
+
+	SCTP_DEBUG_PRINTK("%s: daddr:%pI6 saddr:%pI6",
+		__func__, &daddr->v6.sin6_addr, &saddr->v6.sin6_addr);
+
+	memset(&fl, 0, sizeof(fl));
+	fl.proto = IPPROTO_SCTP;
+	fl.fl_ip_dport = daddr->v6.sin6_port;
+	fl.fl_ip_sport = saddr->v6.sin6_port;
+	ipv6_addr_copy(&fl.fl6_dst, &daddr->v6.sin6_addr);
+	ipv6_addr_copy(&fl.fl6_src, &saddr->v6.sin6_addr);
+
+	if (xfrm_lookup(&init_net, dst_p, &fl, NULL, 0) < 0)
+		return NULL;
+	else
+		return *dst_p;
+}
+
 /* Returns the number of consecutive initial bits that match in the 2 ipv6
  * addresses.
  */
@@ -962,6 +984,7 @@ static struct sctp_af sctp_af_inet6 = {
 	.setsockopt	   = ipv6_setsockopt,
 	.getsockopt	   = ipv6_getsockopt,
 	.get_dst	   = sctp_v6_get_dst,
+	.get_xfrm_dst	   = sctp_v6_get_xfrm_dst,
 	.get_saddr	   = sctp_v6_get_saddr,
 	.copy_addrlist	   = sctp_v6_copy_addrlist,
 	.from_skb	   = sctp_v6_from_skb,
net/sctp/transport.c +3 -0
index be4d63d..f89dd4d 100644
@@ -298,6 +298,9 @@ void sctp_transport_route(struct sctp_transport *transport,
 	else
 		af->get_saddr(opt, asoc, dst, daddr, &transport->saddr);
 
+	if (af->get_xfrm_dst)
+		dst = af->get_xfrm_dst(&dst, daddr, &transport->saddr);
+
 	transport->dst = dst;
 	if ((transport->param_flags & SPP_PMTUD_DISABLE) && transport->pathmtu) {
 		return;
#3 lore raw
In reply to Wei Yongjun
Quoted 10 lines · Wei Yongjun
Quoted 9 lines

What about the PMTU problem?

I've understand that this solution will not work:

You wrote:
"This would work for transmit SCTP packet under IPSEC, the problem is that we can not get the correct PMTU for the transport.Under IPv4, both transmit and the PMTU is correct."

Quoted 7 lines

Yeah, sorry for that, the PMTU problem maybe because I did the wrong thing in the past when I do the same thing. And now when I try to solution it, but works :-( . I do not know whether this implementation has other problem.

Maybe we should do strict route select in sctp_v6_get_dst(), use the address from the asoc or the dev address, do the same thing as IPv4.

Yes. This is what should be done. Folks from windriver at looking at fixing that because IPv6 sourced based policy routing is currently broken.

-vlad

Quoted 90 lines
Quoted 89 lines

Regards,
Nicolas

Quoted 81 lines · Wei Yongjun

IPSec rules are ineffective with IPv6 transmit currently, so this patch make them effective with IPv6.
Idea from Nicolas Dichtel <[email protected]>

---
 include/net/sctp/structs.h |    3 +++
 net/sctp/ipv6.c            |   23 +++++++++++++++++++++++
 net/sctp/transport.c       |    3 +++
 3 files changed, 29 insertions(+), 0 deletions(-)
include/net/sctp/structs.h +3 -0
index ff30177..5fe4df4 100644
@@ -569,6 +569,9 @@ struct sctp_af {
 	struct dst_entry *(*get_dst)	(struct sctp_association *asoc,
 					 union sctp_addr *daddr,
 					 union sctp_addr *saddr);
+	struct dst_entry *(*get_xfrm_dst)(struct dst_entry **dst_p,
+					  union sctp_addr *daddr,
+					  union sctp_addr *saddr);
 	void		(*get_saddr)	(struct sctp_sock *sk,
 					 struct sctp_association *asoc,
 					 struct dst_entry *dst,
net/sctp/ipv6.c +23 -0
index 9fb5d37..09a4c9c 100644
@@ -271,6 +271,28 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
 	return NULL;
 }
 
+static struct dst_entry *sctp_v6_get_xfrm_dst(struct dst_entry **dst_p,
+					       union sctp_addr *daddr,
+					       union sctp_addr *saddr)
+{
+	struct flowi fl;
+
+	SCTP_DEBUG_PRINTK("%s: daddr:%pI6 saddr:%pI6",
+		__func__, &daddr->v6.sin6_addr, &saddr->v6.sin6_addr);
+
+	memset(&fl, 0, sizeof(fl));
+	fl.proto = IPPROTO_SCTP;
+	fl.fl_ip_dport = daddr->v6.sin6_port;
+	fl.fl_ip_sport = saddr->v6.sin6_port;
+	ipv6_addr_copy(&fl.fl6_dst, &daddr->v6.sin6_addr);
+	ipv6_addr_copy(&fl.fl6_src, &saddr->v6.sin6_addr);
+
+	if (xfrm_lookup(&init_net, dst_p, &fl, NULL, 0) < 0)
+		return NULL;
+	else
+		return *dst_p;
+}
+
 /* Returns the number of consecutive initial bits that match in the 2 ipv6
  * addresses.
  */
@@ -962,6 +984,7 @@ static struct sctp_af sctp_af_inet6 = {
 	.setsockopt	   = ipv6_setsockopt,
 	.getsockopt	   = ipv6_getsockopt,
 	.get_dst	   = sctp_v6_get_dst,
+	.get_xfrm_dst	   = sctp_v6_get_xfrm_dst,
 	.get_saddr	   = sctp_v6_get_saddr,
 	.copy_addrlist	   = sctp_v6_copy_addrlist,
 	.from_skb	   = sctp_v6_from_skb,
net/sctp/transport.c +3 -0
index be4d63d..f89dd4d 100644
@@ -298,6 +298,9 @@ void sctp_transport_route(struct sctp_transport *transport,
 	else
 		af->get_saddr(opt, asoc, dst, daddr, &transport->saddr);
 
+	if (af->get_xfrm_dst)
+		dst = af->get_xfrm_dst(&dst, daddr, &transport->saddr);
+
 	transport->dst = dst;
 	if ((transport->param_flags & SPP_PMTUD_DISABLE) && transport->pathmtu) {
 		return;
#4 lore raw
In reply to Wei Yongjun

Another thread began about the source address problem:
http://marc.info/?t7119843800002&r=1&w=2

Maybe we can fix both problems together. It seems that IPv6 lacks some routing operations.

Regards,
Nicolas

Quoted 106 lines · Wei Yongjun
Quoted 9 lines

What about the PMTU problem?

I've understand that this solution will not work:

You wrote:
"This would work for transmit SCTP packet under IPSEC, the problem is that we can not get the correct PMTU for the transport.Under IPv4, both transmit and the PMTU is correct."

Yeah, sorry for that, the PMTU problem maybe because I did the wrong thing in the past when I do the same thing. And now when I try to solution it, but works :-( . I do not know whether this implementation has other problem.

Maybe we should do strict route select in sctp_v6_get_dst(), use the address from the asoc or the dev address, do the same thing as IPv4.

Quoted 87 lines

Regards,
Nicolas

Quoted 81 lines · Wei Yongjun

IPSec rules are ineffective with IPv6 transmit currently, so this patch make them effective with IPv6.
Idea from Nicolas Dichtel <[email protected]>

---
 include/net/sctp/structs.h |    3 +++
 net/sctp/ipv6.c            |   23 +++++++++++++++++++++++
 net/sctp/transport.c       |    3 +++
 3 files changed, 29 insertions(+), 0 deletions(-)
include/net/sctp/structs.h +3 -0
index ff30177..5fe4df4 100644
@@ -569,6 +569,9 @@ struct sctp_af {
 	struct dst_entry *(*get_dst)	(struct sctp_association *asoc,
 					 union sctp_addr *daddr,
 					 union sctp_addr *saddr);
+	struct dst_entry *(*get_xfrm_dst)(struct dst_entry **dst_p,
+					  union sctp_addr *daddr,
+					  union sctp_addr *saddr);
 	void		(*get_saddr)	(struct sctp_sock *sk,
 					 struct sctp_association *asoc,
 					 struct dst_entry *dst,
net/sctp/ipv6.c +23 -0
index 9fb5d37..09a4c9c 100644
@@ -271,6 +271,28 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
 	return NULL;
 }
 
+static struct dst_entry *sctp_v6_get_xfrm_dst(struct dst_entry **dst_p,
+					       union sctp_addr *daddr,
+					       union sctp_addr *saddr)
+{
+	struct flowi fl;
+
+	SCTP_DEBUG_PRINTK("%s: daddr:%pI6 saddr:%pI6",
+		__func__, &daddr->v6.sin6_addr, &saddr->v6.sin6_addr);
+
+	memset(&fl, 0, sizeof(fl));
+	fl.proto = IPPROTO_SCTP;
+	fl.fl_ip_dport = daddr->v6.sin6_port;
+	fl.fl_ip_sport = saddr->v6.sin6_port;
+	ipv6_addr_copy(&fl.fl6_dst, &daddr->v6.sin6_addr);
+	ipv6_addr_copy(&fl.fl6_src, &saddr->v6.sin6_addr);
+
+	if (xfrm_lookup(&init_net, dst_p, &fl, NULL, 0) < 0)
+		return NULL;
+	else
+		return *dst_p;
+}
+
 /* Returns the number of consecutive initial bits that match in the 2 ipv6
  * addresses.
  */
@@ -962,6 +984,7 @@ static struct sctp_af sctp_af_inet6 = {
 	.setsockopt	   = ipv6_setsockopt,
 	.getsockopt	   = ipv6_getsockopt,
 	.get_dst	   = sctp_v6_get_dst,
+	.get_xfrm_dst	   = sctp_v6_get_xfrm_dst,
 	.get_saddr	   = sctp_v6_get_saddr,
 	.copy_addrlist	   = sctp_v6_copy_addrlist,
 	.from_skb	   = sctp_v6_from_skb,
net/sctp/transport.c +3 -0
index be4d63d..f89dd4d 100644
@@ -298,6 +298,9 @@ void sctp_transport_route(struct sctp_transport *transport,
 	else
 		af->get_saddr(opt, asoc, dst, daddr, &transport->saddr);
 
+	if (af->get_xfrm_dst)
+		dst = af->get_xfrm_dst(&dst, daddr, &transport->saddr);
+
 	transport->dst = dst;
 	if ((transport->param_flags & SPP_PMTUD_DISABLE) && transport->pathmtu) {
 		return;