On 16/04/16(Sat) 18:41, Markus Friedl wrote:
> Hi, this matches the IPsec/IPv4 change I committed back in December, but
> since I don't have extensive IPv6 setups it's still not committed. Please
> test, give feedback and it will finally go into the next release.
I hope it will go before the next release! This would help me a lot to
turn the IPv6 forwarding path mpsafe.
ok mpi@
>Index: netinet6/ip6_forward.c
>===================================================================
>RCS file: /cvs/src/sys/netinet6/ip6_forward.c,v
>retrieving revision 1.87
>diff -u -p -u -r1.87 ip6_forward.c
>--- netinet6/ip6_forward.c 29 Mar 2016 11:57:51 -0000 1.87
>+++ netinet6/ip6_forward.c 13 Apr 2016 21:47:09 -0000
>@@ -93,15 +93,7 @@ ip6_forward(struct mbuf *m, int srcrt)
> int error = 0, type = 0, code = 0;
> struct mbuf *mcopy = NULL;
> #ifdef IPSEC
>- u_int8_t sproto = 0;
>- struct m_tag *mtag;
>- union sockaddr_union sdst;
>- struct tdb_ident *tdbi;
>- u_int32_t sspi;
>- struct tdb *tdb;
>-#if NPF > 0
>- struct ifnet *encif;
>-#endif
>+ struct tdb *tdb = NULL;
> #endif /* IPSEC */
> u_int rtableid = 0;
> char src6[INET6_ADDRSTRLEN], dst6[INET6_ADDRSTRLEN];
>@@ -155,64 +147,21 @@ reroute:
> #endif
>
> #ifdef IPSEC
>- if (!ipsec_in_use)
>- goto done_spd;
>-
>- /*
>- * Check if there was an outgoing SA bound to the flow
>- * from a transport protocol.
>- */
>-
>- /* Do we have any pending SAs to apply ? */
>- tdb = ipsp_spd_lookup(m, AF_INET6, sizeof(struct ip6_hdr),
>- &error, IPSP_DIRECTION_OUT, NULL, NULL, 0);
>-
>- if (tdb == NULL) {
>- if (error == 0) {
>- /*
>- * No IPsec processing required, we'll just send the
>- * packet out.
>- */
>- sproto = 0;
>-
>- /* Fall through to routing/multicast handling */
>- } else {
>- /*
>+ if (ipsec_in_use) {
>+ tdb = ip6_output_ipsec_lookup(m, &error, NULL);
>+ if (error != 0) {
>+ /*
> * -EINVAL is used to indicate that the packet should
> * be silently dropped, typically because we've asked
> * key management for an SA.
> */
>- if (error == -EINVAL) /* Should silently drop packet */
>+ if (error == -EINVAL) /* Should silently drop packet */
> error = 0;
>
> m_freem(m);
> goto freecopy;
> }
>- } else {
>- /* Loop detection */
>- for (mtag = m_tag_first(m); mtag != NULL;
>- mtag = m_tag_next(m, mtag)) {
>- if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE)
>- continue;
>- tdbi = (struct tdb_ident *)(mtag + 1);
>- if (tdbi->spi == tdb->tdb_spi &&
>- tdbi->proto == tdb->tdb_sproto &&
>- tdbi->rdomain == tdb->tdb_rdomain &&
>- !bcmp(&tdbi->dst, &tdb->tdb_dst,
>- sizeof(union sockaddr_union))) {
>- sproto = 0; /* mark as no-IPsec-needed */
>- goto done_spd;
>- }
>- }
>-
>- /* We need to do IPsec */
>- bcopy(&tdb->tdb_dst, &sdst, sizeof(sdst));
>- sspi = tdb->tdb_spi;
>- sproto = tdb->tdb_sproto;
> }
>-
>- /* Fall through to the routing/multicast handling code */
>- done_spd:
> #endif /* IPSEC */
>
> #if NPF > 0
>@@ -313,40 +262,12 @@ reroute:
> * XXX ipsp_process_packet() calls ip6_output(), and there'll be no
> * PMTU notification. is it okay?
> */
>- if (sproto != 0) {
>- tdb = gettdb(rtable_l2(m->m_pkthdr.ph_rtableid),
>- sspi, &sdst, sproto);
>- if (tdb == NULL) {
>- error = EHOSTUNREACH;
>- m_freem(m);
>- goto senderr; /*XXX*/
>- }
>-
>-#if NPF > 0
>- if ((encif = enc_getif(tdb->tdb_rdomain,
>- tdb->tdb_tap)) == NULL ||
>- pf_test(AF_INET6, PF_FWD, encif, &m) != PF_PASS) {
>- error = EHOSTUNREACH;
>- m_freem(m);
>- goto senderr;
>- }
>- if (m == NULL)
>- goto senderr;
>- /*
>- * PF_TAG_REROUTE handling or not...
>- * Packet is entering IPsec so the routing is
>- * already overruled by the IPsec policy.
>- * Until now the change was not reconsidered.
>- * What's the behaviour?
>- */
>- in6_proto_cksum_out(m, encif);
>-#endif
>- m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */
>-
>+ if (tdb != NULL) {
> /* Callee frees mbuf */
>- error = ipsp_process_packet(m, tdb, AF_INET6, 0);
>- m_freem(mcopy);
>- goto freert;
>+ error = ip6_output_ipsec_send(tdb, m, 0, 1);
>+ if (error)
>+ goto senderr;
>+ goto freecopy;
> }
> #endif /* IPSEC */
>
>Index: netinet6/ip6_output.c
>===================================================================
>RCS file: /cvs/src/sys/netinet6/ip6_output.c,v
>retrieving revision 1.204
>diff -u -p -u -r1.204 ip6_output.c
>--- netinet6/ip6_output.c 21 Jan 2016 11:23:48 -0000 1.204
>+++ netinet6/ip6_output.c 13 Apr 2016 21:47:09 -0000
>@@ -172,14 +172,7 @@ ip6_output(struct mbuf *m0, struct ip6_p
> int hdrsplit = 0;
> u_int8_t sproto = 0;
> #ifdef IPSEC
>- struct m_tag *mtag;
>- union sockaddr_union sdst;
>- struct tdb_ident *tdbi;
>- u_int32_t sspi;
>- struct tdb *tdb;
>-#if NPF > 0
>- struct ifnet *encif;
>-#endif
>+ struct tdb *tdb = NULL;
> #endif /* IPSEC */
>
> #ifdef IPSEC
>@@ -215,28 +208,9 @@ ip6_output(struct mbuf *m0, struct ip6_p
> }
>
> #ifdef IPSEC
>- if (!ipsec_in_use && !inp)
>- goto done_spd;
>-
>- /*
>- * Check if there was an outgoing SA bound to the flow
>- * from a transport protocol.
>- */
>-
>- /* Do we have any pending SAs to apply ? */
>- tdb = ipsp_spd_lookup(m, AF_INET6, sizeof(struct ip6_hdr),
>- &error, IPSP_DIRECTION_OUT, NULL, inp, 0);
>-
>- if (tdb == NULL) {
>- if (error == 0) {
>- /*
>- * No IPsec processing required, we'll just send the
>- * packet out.
>- */
>- sproto = 0;
>-
>- /* Fall through to routing/multicast handling */
>- } else {
>+ if (ipsec_in_use || inp) {
>+ tdb = ip6_output_ipsec_lookup(m, &error, inp);
>+ if (error != 0) {
> /*
> * -EINVAL is used to indicate that the packet should
> * be silently dropped, typically because we've asked
>@@ -247,31 +221,7 @@ ip6_output(struct mbuf *m0, struct ip6_p
>
> goto freehdrs;
> }
>- } else {
>- /* Loop detection */
>- for (mtag = m_tag_first(m); mtag != NULL;
>- mtag = m_tag_next(m, mtag)) {
>- if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE)
>- continue;
>- tdbi = (struct tdb_ident *)(mtag + 1);
>- if (tdbi->spi == tdb->tdb_spi &&
>- tdbi->proto == tdb->tdb_sproto &&
>- tdbi->rdomain == tdb->tdb_rdomain &&
>- !bcmp(&tdbi->dst, &tdb->tdb_dst,
>- sizeof(union sockaddr_union))) {
>- sproto = 0; /* mark as no-IPsec-needed */
>- goto done_spd;
>- }
>- }
>-
>- /* We need to do IPsec */
>- bcopy(&tdb->tdb_dst, &sdst, sizeof(sdst));
>- sspi = tdb->tdb_spi;
>- sproto = tdb->tdb_sproto;
> }
>-
>- /* Fall through to the routing/multicast handling code */
>- done_spd:
> #endif /* IPSEC */
>
> /*
>@@ -469,55 +419,19 @@ reroute:
> }
>
> #ifdef IPSEC
>- /*
>- * Check if the packet needs encapsulation.
>- * ipsp_process_packet will never come back to here.
>- */
>- if (sproto != 0) {
>+ if (tdb) {
> /*
> * XXX what should we do if ip6_hlim == 0 and the
> * packet gets tunneled?
> */
>-
>- tdb = gettdb(rtable_l2(m->m_pkthdr.ph_rtableid),
>- sspi, &sdst, sproto);
>- if (tdb == NULL) {
>- error = EHOSTUNREACH;
>- m_freem(m);
>- goto done;
>- }
>-
>-#if NPF > 0
>- if ((encif = enc_getif(tdb->tdb_rdomain,
>- tdb->tdb_tap)) == NULL ||
>- pf_test(AF_INET6, PF_OUT, encif, &m) != PF_PASS) {
>- error = EHOSTUNREACH;
>- m_freem(m);
>- goto done;
>- }
>- if (m == NULL)
>- goto done;
>- /*
>- * PF_TAG_REROUTE handling or not...
>- * Packet is entering IPsec so the routing is
>- * already overruled by the IPsec policy.
>- * Until now the change was not reconsidered.
>- * What's the behaviour?
>- */
>- in6_proto_cksum_out(m, encif);
>-#endif
>- m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */
>-
>- /* Callee frees mbuf */
> /*
> * if we are source-routing, do not attempt to tunnel the
> * packet just because ip6_dst is different from what tdb has.
> * XXX
> */
>- error = ipsp_process_packet(m, tdb, AF_INET6,
>- exthdrs.ip6e_rthdr ? 1 : 0);
>-
>- return error; /* Nothing more to be done */
>+ error = ip6_output_ipsec_send(tdb, m,
>+ exthdrs.ip6e_rthdr ? 1 : 0, 0);
>+ goto done;
> }
> #endif /* IPSEC */
>
>@@ -2944,3 +2858,70 @@ in6_proto_cksum_out(struct mbuf *m, stru
> m->m_pkthdr.csum_flags &= ~M_ICMP_CSUM_OUT; /* Clear */
> }
> }
>+
>+#ifdef IPSEC
>+struct tdb *
>+ip6_output_ipsec_lookup(struct mbuf *m, int *error, struct inpcb *inp)
>+{
>+ struct tdb *tdb;
>+ struct m_tag *mtag;
>+ struct tdb_ident *tdbi;
>+
>+ /*
>+ * Check if there was an outgoing SA bound to the flow
>+ * from a transport protocol.
>+ */
>+
>+ /* Do we have any pending SAs to apply ? */
>+ tdb = ipsp_spd_lookup(m, AF_INET6, sizeof(struct ip6_hdr),
>+ error, IPSP_DIRECTION_OUT, NULL, inp, 0);
>+
>+ if (tdb != NULL) {
>+ /* Loop detection */
>+ for (mtag = m_tag_first(m); mtag != NULL;
>+ mtag = m_tag_next(m, mtag)) {
>+ if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE)
>+ continue;
>+ tdbi = (struct tdb_ident *)(mtag + 1);
>+ if (tdbi->spi == tdb->tdb_spi &&
>+ tdbi->proto == tdb->tdb_sproto &&
>+ tdbi->rdomain == tdb->tdb_rdomain &&
>+ !bcmp(&tdbi->dst, &tdb->tdb_dst,
>+ sizeof(union sockaddr_union)))
>+ tdb = NULL;
>+ }
>+ /* We need to do IPsec */
>+ }
>+ return tdb;
>+}
>+
>+int
>+ip6_output_ipsec_send(struct tdb *tdb, struct mbuf *m, int tunalready, int
>fwd)
>+{
>+#if NPF > 0
>+ struct ifnet *encif;
>+#endif
>+
>+#if NPF > 0
>+ if ((encif = enc_getif(tdb->tdb_rdomain, tdb->tdb_tap)) == NULL ||
>+ pf_test(AF_INET6, fwd ? PF_FWD : PF_OUT, encif, &m) != PF_PASS) {
>+ m_freem(m);
>+ return EHOSTUNREACH;
>+ }
>+ if (m == NULL)
>+ return 0;
>+ /*
>+ * PF_TAG_REROUTE handling or not...
>+ * Packet is entering IPsec so the routing is
>+ * already overruled by the IPsec policy.
>+ * Until now the change was not reconsidered.
>+ * What's the behaviour?
>+ */
>+ in6_proto_cksum_out(m, encif);
>+#endif
>+ m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */
>+
>+ /* Callee frees mbuf */
>+ return ipsp_process_packet(m, tdb, AF_INET6, tunalready);
>+}
>+#endif /* IPSEC */
>Index: netinet6/ip6_var.h
>===================================================================
>RCS file: /cvs/src/sys/netinet6/ip6_var.h,v
>retrieving revision 1.57
>diff -u -p -u -r1.57 ip6_var.h
>--- netinet6/ip6_var.h 3 Dec 2015 21:11:54 -0000 1.57
>+++ netinet6/ip6_var.h 13 Apr 2016 21:47:08 -0000
>@@ -304,6 +304,14 @@ struct rtentry *in6_selectroute(struct s
> struct route_in6 *, unsigned int rtableid);
>
> u_int32_t ip6_randomflowlabel(void);
>+
>+#ifdef IPSEC
>+struct tdb;
>+struct tdb *
>+ ip6_output_ipsec_lookup(struct mbuf *, int *, struct inpcb *);
>+int ip6_output_ipsec_send(struct tdb *, struct mbuf *, int, int);
>+#endif /* IPSEC */
>+
> #endif /* _KERNEL */
>
> #endif /* !_NETINET6_IP6_VAR_H_ */