mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-29 12:03:03 +00:00
Fix the source address selection for boundall sockets
when sending INITs to a global IPv4 address having only private IPv4 address. Allow the usage of a private address and make sure that no other private address will be used by the association. Initial work was done by rrs@. MFC after: 1 week.
This commit is contained in:
parent
e712713751
commit
96f4bcfff2
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=221904
@ -2022,7 +2022,8 @@ sctp_add_addr_to_mbuf(struct mbuf *m, struct sctp_ifa *ifa)
|
||||
|
||||
|
||||
struct mbuf *
|
||||
sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp, struct sctp_scoping *scope,
|
||||
sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
struct sctp_scoping *scope,
|
||||
struct mbuf *m_at, int cnt_inits_to)
|
||||
{
|
||||
struct sctp_vrf *vrf = NULL;
|
||||
@ -2056,6 +2057,9 @@ sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp, struct sctp_scoping *scope,
|
||||
continue;
|
||||
}
|
||||
LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) {
|
||||
if (sctp_is_addr_restricted(stcb, sctp_ifap)) {
|
||||
continue;
|
||||
}
|
||||
if (sctp_is_address_in_scope(sctp_ifap,
|
||||
scope->ipv4_addr_legal,
|
||||
scope->ipv6_addr_legal,
|
||||
@ -2088,6 +2092,9 @@ sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp, struct sctp_scoping *scope,
|
||||
continue;
|
||||
}
|
||||
LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) {
|
||||
if (sctp_is_addr_restricted(stcb, sctp_ifap)) {
|
||||
continue;
|
||||
}
|
||||
if (sctp_is_address_in_scope(sctp_ifap,
|
||||
scope->ipv4_addr_legal,
|
||||
scope->ipv6_addr_legal,
|
||||
@ -2295,32 +2302,46 @@ sctp_is_ifa_addr_acceptable(struct sctp_ifa *ifa,
|
||||
{
|
||||
uint8_t dest_is_global = 0;
|
||||
|
||||
/*
|
||||
/**
|
||||
* Here we determine if its a acceptable address. A acceptable
|
||||
* address means it is the same scope or higher scope but we can
|
||||
* allow for NAT which means its ok to have a global dest and a
|
||||
* private src.
|
||||
*
|
||||
*
|
||||
* L = loopback, P = private, G = global
|
||||
* ----------------------------------------- src | dest | result
|
||||
* ----------------------------------------- L | L | yes
|
||||
* ----------------------------------------- P | L |
|
||||
* yes-v4 no-v6 ----------------------------------------- G |
|
||||
* L | yes ----------------------------------------- L |
|
||||
* P | no ----------------------------------------- P | P
|
||||
* | yes ----------------------------------------- G | P
|
||||
* | yes - May not work -----------------------------------------
|
||||
* L | G | no ----------------------------------------- P
|
||||
* | G | yes - May not work
|
||||
* ----------------------------------------- G | G | yes
|
||||
* -----------------------------------------
|
||||
* src | dest | result
|
||||
* -----------------------------------------
|
||||
* L | L | yes
|
||||
* -----------------------------------------
|
||||
* P | L | yes-v4 no-v6
|
||||
* -----------------------------------------
|
||||
* G | L | yes
|
||||
* -----------------------------------------
|
||||
* L | P | no
|
||||
* -----------------------------------------
|
||||
* P | P | yes
|
||||
* -----------------------------------------
|
||||
* G | P | yes - May not work
|
||||
* -----------------------------------------
|
||||
* L | G | no
|
||||
* -----------------------------------------
|
||||
* P | G | yes - May not work
|
||||
* -----------------------------------------
|
||||
* G | G | yes
|
||||
* -----------------------------------------
|
||||
*/
|
||||
|
||||
if (ifa->address.sa.sa_family != fam) {
|
||||
/* forget non matching family */
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT3, "ifa_fam:%d fam:%d\n",
|
||||
ifa->address.sa.sa_family, fam);
|
||||
return (NULL);
|
||||
}
|
||||
/* Ok the address may be ok */
|
||||
SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT3, &ifa->address.sa);
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT3, "dst_is_loop:%d dest_is_priv:%d\n",
|
||||
dest_is_loop, dest_is_priv);
|
||||
if ((dest_is_loop == 0) && (dest_is_priv == 0)) {
|
||||
dest_is_global = 1;
|
||||
}
|
||||
@ -2342,12 +2363,19 @@ sctp_is_ifa_addr_acceptable(struct sctp_ifa *ifa,
|
||||
* theory be done slicker (it used to be), but this is
|
||||
* straightforward and easier to validate :-)
|
||||
*/
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT3, "ifa->src_is_loop:%d dest_is_priv:%d\n",
|
||||
ifa->src_is_loop,
|
||||
dest_is_priv);
|
||||
if ((ifa->src_is_loop == 1) && (dest_is_priv)) {
|
||||
return (NULL);
|
||||
}
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT3, "ifa->src_is_loop:%d dest_is_glob:%d\n",
|
||||
ifa->src_is_loop,
|
||||
dest_is_global);
|
||||
if ((ifa->src_is_loop == 1) && (dest_is_global)) {
|
||||
return (NULL);
|
||||
}
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT3, "address is acceptable\n");
|
||||
/* its an acceptable address */
|
||||
return (ifa);
|
||||
}
|
||||
@ -2854,6 +2882,10 @@ sctp_choose_boundall(struct sctp_inpcb *inp,
|
||||
uint32_t ifn_index;
|
||||
struct sctp_vrf *vrf;
|
||||
|
||||
#ifdef INET
|
||||
int retried = 0;
|
||||
|
||||
#endif
|
||||
/*-
|
||||
* For boundall we can use any address in the association.
|
||||
* If non_asoc_addr_ok is set we can use any address (at least in
|
||||
@ -2874,6 +2906,7 @@ sctp_choose_boundall(struct sctp_inpcb *inp,
|
||||
|
||||
ifn = SCTP_GET_IFN_VOID_FROM_ROUTE(ro);
|
||||
ifn_index = SCTP_GET_IF_INDEX_FROM_ROUTE(ro);
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT2, "ifn from route:%p ifn_index:%d\n", ifn, ifn_index);
|
||||
emit_ifn = looked_at = sctp_ifn = sctp_find_ifn(ifn, ifn_index);
|
||||
if (sctp_ifn == NULL) {
|
||||
/* ?? We don't have this guy ?? */
|
||||
@ -2982,22 +3015,30 @@ sctp_choose_boundall(struct sctp_inpcb *inp,
|
||||
}
|
||||
atomic_add_int(&sifa->refcount, 1);
|
||||
return (sifa);
|
||||
|
||||
}
|
||||
|
||||
#ifdef INET
|
||||
again_with_private_addresses_allowed:
|
||||
#endif
|
||||
/* plan_c: do we have an acceptable address on the emit interface */
|
||||
sifa = NULL;
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT2, "Trying Plan C: find acceptable on interface\n");
|
||||
if (emit_ifn == NULL) {
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT2, "Jump to Plan D - no emit_ifn\n");
|
||||
goto plan_d;
|
||||
}
|
||||
LIST_FOREACH(sctp_ifa, &emit_ifn->ifalist, next_ifa) {
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT2, "ifa:%p\n", sctp_ifa);
|
||||
if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) &&
|
||||
(non_asoc_addr_ok == 0))
|
||||
(non_asoc_addr_ok == 0)) {
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT2, "Defer\n");
|
||||
continue;
|
||||
}
|
||||
sifa = sctp_is_ifa_addr_acceptable(sctp_ifa, dest_is_loop,
|
||||
dest_is_priv, fam);
|
||||
if (sifa == NULL)
|
||||
if (sifa == NULL) {
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT2, "IFA not acceptable\n");
|
||||
continue;
|
||||
}
|
||||
if (stcb) {
|
||||
if (sctp_is_address_in_scope(sifa,
|
||||
stcb->asoc.ipv4_addr_legal,
|
||||
@ -3006,6 +3047,8 @@ sctp_choose_boundall(struct sctp_inpcb *inp,
|
||||
stcb->asoc.ipv4_local_scope,
|
||||
stcb->asoc.local_scope,
|
||||
stcb->asoc.site_scope, 0) == 0) {
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT2, "NOT in scope\n");
|
||||
sifa = NULL;
|
||||
continue;
|
||||
}
|
||||
if (((non_asoc_addr_ok == 0) &&
|
||||
@ -3017,11 +3060,15 @@ sctp_choose_boundall(struct sctp_inpcb *inp,
|
||||
* It is restricted for some reason..
|
||||
* probably not yet added.
|
||||
*/
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT2, "Its resticted\n");
|
||||
sifa = NULL;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
printf("Stcb is null - no print\n");
|
||||
}
|
||||
atomic_add_int(&sifa->refcount, 1);
|
||||
return (sifa);
|
||||
goto out;
|
||||
}
|
||||
plan_d:
|
||||
/*
|
||||
@ -3030,16 +3077,12 @@ sctp_choose_boundall(struct sctp_inpcb *inp,
|
||||
* out and see if we can find an acceptable address somewhere
|
||||
* amongst all interfaces.
|
||||
*/
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT2, "Trying Plan D\n");
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT2, "Trying Plan D looked_at is %p\n", looked_at);
|
||||
LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
|
||||
if (dest_is_loop == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
|
||||
/* wrong base scope */
|
||||
continue;
|
||||
}
|
||||
if ((sctp_ifn == looked_at) && looked_at)
|
||||
/* already looked at this guy */
|
||||
continue;
|
||||
|
||||
LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
|
||||
if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) &&
|
||||
(non_asoc_addr_ok == 0))
|
||||
@ -3057,6 +3100,7 @@ sctp_choose_boundall(struct sctp_inpcb *inp,
|
||||
stcb->asoc.ipv4_local_scope,
|
||||
stcb->asoc.local_scope,
|
||||
stcb->asoc.site_scope, 0) == 0) {
|
||||
sifa = NULL;
|
||||
continue;
|
||||
}
|
||||
if (((non_asoc_addr_ok == 0) &&
|
||||
@ -3068,19 +3112,81 @@ sctp_choose_boundall(struct sctp_inpcb *inp,
|
||||
* It is restricted for some
|
||||
* reason.. probably not yet added.
|
||||
*/
|
||||
sifa = NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
atomic_add_int(&sifa->refcount, 1);
|
||||
return (sifa);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Ok we can find NO address to source from that is not on our
|
||||
* restricted list and non_asoc_address is NOT ok, or it is on our
|
||||
* restricted list. We can't source to it :-(
|
||||
*/
|
||||
return (NULL);
|
||||
#ifdef INET
|
||||
if ((retried == 0) && (stcb->asoc.ipv4_local_scope == 0)) {
|
||||
stcb->asoc.ipv4_local_scope = 1;
|
||||
retried = 1;
|
||||
goto again_with_private_addresses_allowed;
|
||||
} else if (retried == 1) {
|
||||
stcb->asoc.ipv4_local_scope = 0;
|
||||
}
|
||||
#endif
|
||||
out:
|
||||
if (sifa) {
|
||||
#ifdef INET
|
||||
if (retried == 1) {
|
||||
LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
|
||||
if (dest_is_loop == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
|
||||
/* wrong base scope */
|
||||
continue;
|
||||
}
|
||||
LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
|
||||
struct sctp_ifa *tmp_sifa;
|
||||
|
||||
if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) &&
|
||||
(non_asoc_addr_ok == 0))
|
||||
continue;
|
||||
tmp_sifa = sctp_is_ifa_addr_acceptable(sctp_ifa,
|
||||
dest_is_loop,
|
||||
dest_is_priv, fam);
|
||||
if (tmp_sifa == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (tmp_sifa == sifa) {
|
||||
continue;
|
||||
}
|
||||
if (stcb) {
|
||||
if (sctp_is_address_in_scope(tmp_sifa,
|
||||
stcb->asoc.ipv4_addr_legal,
|
||||
stcb->asoc.ipv6_addr_legal,
|
||||
stcb->asoc.loopback_scope,
|
||||
stcb->asoc.ipv4_local_scope,
|
||||
stcb->asoc.local_scope,
|
||||
stcb->asoc.site_scope, 0) == 0) {
|
||||
continue;
|
||||
}
|
||||
if (((non_asoc_addr_ok == 0) &&
|
||||
(sctp_is_addr_restricted(stcb, tmp_sifa))) ||
|
||||
(non_asoc_addr_ok &&
|
||||
(sctp_is_addr_restricted(stcb, tmp_sifa)) &&
|
||||
(!sctp_is_addr_pending(stcb, tmp_sifa)))) {
|
||||
/*
|
||||
* It is restricted
|
||||
* for some reason..
|
||||
* probably not yet
|
||||
* added.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ((tmp_sifa->address.sin.sin_family == AF_INET) &&
|
||||
(IN4_ISPRIVATE_ADDRESS(&(tmp_sifa->address.sin.sin_addr)))) {
|
||||
sctp_add_local_addr_restricted(stcb, tmp_sifa);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
atomic_add_int(&sifa->refcount, 1);
|
||||
}
|
||||
#endif
|
||||
return (sifa);
|
||||
}
|
||||
|
||||
|
||||
@ -3106,7 +3212,7 @@ sctp_source_address_selection(struct sctp_inpcb *inp,
|
||||
|
||||
#endif
|
||||
|
||||
/*-
|
||||
/**
|
||||
* Rules: - Find the route if needed, cache if I can. - Look at
|
||||
* interface address in route, Is it in the bound list. If so we
|
||||
* have the best source. - If not we must rotate amongst the
|
||||
@ -3509,15 +3615,17 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
|
||||
)
|
||||
/* nofragment_flag to tell if IP_DF should be set (IPv4 only) */
|
||||
{
|
||||
/*
|
||||
* Given a mbuf chain (via SCTP_BUF_NEXT()) that holds a packet
|
||||
* header WITH an SCTPHDR but no IP header, endpoint inp and sa
|
||||
* structure: - fill in the HMAC digest of any AUTH chunk in the
|
||||
* packet. - calculate and fill in the SCTP checksum. - prepend an
|
||||
* IP address header. - if boundall use INADDR_ANY. - if
|
||||
* boundspecific do source address selection. - set fragmentation
|
||||
* option for ipV4. - On return from IP output, check/adjust mtu
|
||||
* size of output interface and smallest_mtu size as well.
|
||||
/**
|
||||
* Given a mbuf chain (via SCTP_BUF_NEXT()) that holds a packet header
|
||||
* WITH an SCTPHDR but no IP header, endpoint inp and sa structure:
|
||||
* - fill in the HMAC digest of any AUTH chunk in the packet.
|
||||
* - calculate and fill in the SCTP checksum.
|
||||
* - prepend an IP address header.
|
||||
* - if boundall use INADDR_ANY.
|
||||
* - if boundspecific do source address selection.
|
||||
* - set fragmentation option for ipV4.
|
||||
* - On return from IP output, check/adjust mtu size of output
|
||||
* interface and smallest_mtu size as well.
|
||||
*/
|
||||
/* Will need ifdefs around this */
|
||||
struct mbuf *o_pak;
|
||||
@ -4409,7 +4517,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
|
||||
scp.local_scope = stcb->asoc.local_scope;
|
||||
scp.site_scope = stcb->asoc.site_scope;
|
||||
|
||||
m_at = sctp_add_addresses_to_i_ia(inp, &scp, m_at, cnt_inits_to);
|
||||
m_at = sctp_add_addresses_to_i_ia(inp, stcb, &scp, m_at, cnt_inits_to);
|
||||
}
|
||||
|
||||
/* calulate the size and update pkt header and chunk header */
|
||||
@ -5538,7 +5646,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
scp.ipv4_local_scope = stc.ipv4_scope;
|
||||
scp.local_scope = stc.local_scope;
|
||||
scp.site_scope = stc.site_scope;
|
||||
m_at = sctp_add_addresses_to_i_ia(inp, &scp, m_at, cnt_inits_to);
|
||||
m_at = sctp_add_addresses_to_i_ia(inp, stcb, &scp, m_at, cnt_inits_to);
|
||||
}
|
||||
|
||||
/* tack on the operational error if present */
|
||||
|
@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
struct mbuf *
|
||||
sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp,
|
||||
struct sctp_tcb *stcb,
|
||||
struct sctp_scoping *scope,
|
||||
struct mbuf *m_at,
|
||||
int cnt_inits_to);
|
||||
|
Loading…
Reference in New Issue
Block a user