The branch main has been updated by sobomax:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=461e6f23db3b9794e6af88b381b066a2c0463d1c

commit 461e6f23db3b9794e6af88b381b066a2c0463d1c
Author:     Maxim Sobolev <sobo...@freebsd.org>
AuthorDate: 2021-10-07 20:41:40 +0000
Commit:     Maxim Sobolev <sobo...@freebsd.org>
CommitDate: 2021-10-15 23:48:12 +0000

    Fix fragmented UDP packets handling since rev.360967.
    
    Consider IP_MF flag when checking length of the UDP packet to
    match the declared value.
    
    Sponsored by:   Sippy Software, Inc.
    Differential Revision:  https://reviews.freebsd.org/D32363
    MFC after:      2 weeks
---
 sys/netinet/libalias/alias.c | 225 +++++++++++++++++++++++--------------------
 1 file changed, 120 insertions(+), 105 deletions(-)

diff --git a/sys/netinet/libalias/alias.c b/sys/netinet/libalias/alias.c
index 39e9b060623d..37f5bd5a1db1 100644
--- a/sys/netinet/libalias/alias.c
+++ b/sys/netinet/libalias/alias.c
@@ -721,21 +721,37 @@ ProtoAliasOut(struct libalias *la, struct ip *pip,
        return (PKT_ALIAS_IGNORED);
 }
 
+#define MF_ISSET(_pip) (ntohs((_pip)->ip_off) & IP_MF)
+#define FRAG_NO_HDR(_pip) (ntohs((_pip)->ip_off) & IP_OFFMASK)
+
+static struct udphdr *
+ValidateUdpLength(struct ip *pip)
+{
+       struct udphdr *ud;
+       size_t dlen;
+
+#ifdef _KERNEL
+       KASSERT(!FRAG_NO_HDR(pip), ("header-less fragment isn't expected 
here"));
+#endif
+       dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
+       if (dlen < sizeof(struct udphdr))
+               return (NULL);
+       ud = (struct udphdr *)ip_next(pip);
+       if (!MF_ISSET(pip) && dlen < ntohs(ud->uh_ulen))
+               return (NULL);
+       return (ud);
+}
+
 static int
 UdpAliasIn(struct libalias *la, struct ip *pip)
 {
        struct udphdr *ud;
        struct alias_link *lnk;
-       size_t dlen;
 
        LIBALIAS_LOCK_ASSERT(la);
 
-       dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
-       if (dlen < sizeof(struct udphdr))
-               return (PKT_ALIAS_IGNORED);
-
-       ud = (struct udphdr *)ip_next(pip);
-       if (dlen < ntohs(ud->uh_ulen))
+       ud = ValidateUdpLength(pip);
+       if (ud == NULL)
                return (PKT_ALIAS_IGNORED);
 
        lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
@@ -828,19 +844,14 @@ UdpAliasOut(struct libalias *la, struct ip *pip, int 
maxpacketsize, int create)
        u_short proxy_server_port;
        int proxy_type;
        int error;
-       size_t dlen;
 
        LIBALIAS_LOCK_ASSERT(la);
 
-       /* Return if proxy-only mode is enabled and not proxyrule found.*/
-       dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
-       if (dlen < sizeof(struct udphdr))
-               return (PKT_ALIAS_IGNORED);
-
-       ud = (struct udphdr *)ip_next(pip);
-       if (dlen < ntohs(ud->uh_ulen))
+       ud = ValidateUdpLength(pip);
+       if (ud == NULL)
                return (PKT_ALIAS_IGNORED);
 
+       /* Return if proxy-only mode is enabled and not proxyrule found.*/
        proxy_type = ProxyCheck(la, &proxy_server_address, &proxy_server_port,
            pip->ip_src, pip->ip_dst, ud->uh_dport, pip->ip_p);
        if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
@@ -1339,64 +1350,65 @@ LibAliasInLocked(struct libalias *la, struct ip *pip, 
int maxpacketsize)
                goto getout;
        }
 
+       if (FRAG_NO_HDR(pip)) {
+               iresult = FragmentIn(la, pip->ip_src, pip, pip->ip_id,
+                   &pip->ip_sum);
+               goto getout;
+       }
+
        iresult = PKT_ALIAS_IGNORED;
-       if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
-               switch (pip->ip_p) {
-               case IPPROTO_ICMP:
-                       iresult = IcmpAliasIn(la, pip);
-                       break;
-               case IPPROTO_UDP:
-                       iresult = UdpAliasIn(la, pip);
-                       break;
-               case IPPROTO_TCP:
-                       iresult = TcpAliasIn(la, pip);
-                       break;
+       switch (pip->ip_p) {
+       case IPPROTO_ICMP:
+               iresult = IcmpAliasIn(la, pip);
+               break;
+       case IPPROTO_UDP:
+               iresult = UdpAliasIn(la, pip);
+               break;
+       case IPPROTO_TCP:
+               iresult = TcpAliasIn(la, pip);
+               break;
 #ifdef _KERNEL
-               case IPPROTO_SCTP:
-                       iresult = SctpAlias(la, pip, SN_TO_LOCAL);
-                       break;
+       case IPPROTO_SCTP:
+               iresult = SctpAlias(la, pip, SN_TO_LOCAL);
+               break;
 #endif
-               case IPPROTO_GRE: {
-                       int error;
-                       struct alias_data ad = {
-                               .lnk = NULL,
-                               .oaddr = NULL,
-                               .aaddr = NULL,
-                               .aport = NULL,
-                               .sport = NULL,
-                               .dport = NULL,
-                               .maxpktsize = 0
-                       };
-
-                       /* Walk out chain. */
-                       error = find_handler(IN, IP, la, pip, &ad);
-                       if (error == 0)
-                               iresult = PKT_ALIAS_OK;
-                       else
-                               iresult = ProtoAliasIn(la, pip->ip_src,
-                                   pip, pip->ip_p, &pip->ip_sum);
-                       break;
-               }
-               default:
-                       iresult = ProtoAliasIn(la, pip->ip_src, pip,
-                           pip->ip_p, &pip->ip_sum);
-                       break;
-               }
+       case IPPROTO_GRE: {
+               int error;
+               struct alias_data ad = {
+                       .lnk = NULL,
+                       .oaddr = NULL,
+                       .aaddr = NULL,
+                       .aport = NULL,
+                       .sport = NULL,
+                       .dport = NULL,
+                       .maxpktsize = 0
+               };
 
-               if (ntohs(pip->ip_off) & IP_MF) {
-                       struct alias_link *lnk;
+               /* Walk out chain. */
+               error = find_handler(IN, IP, la, pip, &ad);
+               if (error == 0)
+                       iresult = PKT_ALIAS_OK;
+               else
+                       iresult = ProtoAliasIn(la, pip->ip_src,
+                           pip, pip->ip_p, &pip->ip_sum);
+               break;
+       }
+       default:
+               iresult = ProtoAliasIn(la, pip->ip_src, pip,
+                   pip->ip_p, &pip->ip_sum);
+               break;
+       }
 
-                       lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, 
pip->ip_id);
-                       if (lnk != NULL) {
-                               iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
-                               SetFragmentAddr(lnk, pip->ip_dst);
-                       } else {
-                               iresult = PKT_ALIAS_ERROR;
-                       }
+       if (MF_ISSET(pip)) {
+               struct alias_link *lnk;
+
+               lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
+               if (lnk != NULL) {
+                       iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
+                       SetFragmentAddr(lnk, pip->ip_dst);
+               } else {
+                       iresult = PKT_ALIAS_ERROR;
                }
-       } else {
-               iresult = FragmentIn(la, pip->ip_src, pip, pip->ip_id,
-                   &pip->ip_sum);
        }
 
 getout:
@@ -1492,52 +1504,55 @@ LibAliasOutLocked(struct libalias *la,
        } else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
                SetDefaultAliasAddress(la, pip->ip_src);
        }
+
+       if (FRAG_NO_HDR(pip)) {
+               iresult = FragmentOut(la, pip, &pip->ip_sum);
+               goto getout_restore;
+       }
+
        iresult = PKT_ALIAS_IGNORED;
-       if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
-               switch (pip->ip_p) {
-               case IPPROTO_ICMP:
-                       iresult = IcmpAliasOut(la, pip, create);
-                       break;
-               case IPPROTO_UDP:
-                       iresult = UdpAliasOut(la, pip, maxpacketsize, create);
-                       break;
-               case IPPROTO_TCP:
-                       iresult = TcpAliasOut(la, pip, maxpacketsize, create);
-                       break;
+       switch (pip->ip_p) {
+       case IPPROTO_ICMP:
+               iresult = IcmpAliasOut(la, pip, create);
+               break;
+       case IPPROTO_UDP:
+               iresult = UdpAliasOut(la, pip, maxpacketsize, create);
+               break;
+       case IPPROTO_TCP:
+               iresult = TcpAliasOut(la, pip, maxpacketsize, create);
+               break;
 #ifdef _KERNEL
-               case IPPROTO_SCTP:
-                       iresult = SctpAlias(la, pip, SN_TO_GLOBAL);
-                       break;
+       case IPPROTO_SCTP:
+               iresult = SctpAlias(la, pip, SN_TO_GLOBAL);
+               break;
 #endif
-               case IPPROTO_GRE: {
-                       int error;
-                       struct alias_data ad = {
-                               .lnk = NULL,
-                               .oaddr = NULL,
-                               .aaddr = NULL,
-                               .aport = NULL,
-                               .sport = NULL,
-                               .dport = NULL,
-                               .maxpktsize = 0
-                       };
-                       /* Walk out chain. */
-                       error = find_handler(OUT, IP, la, pip, &ad);
-                       if (error == 0)
-                               iresult = PKT_ALIAS_OK;
-                       else
-                               iresult = ProtoAliasOut(la, pip,
-                                   pip->ip_dst, pip->ip_p, &pip->ip_sum, 
create);
-                       break;
-               }
-               default:
+       case IPPROTO_GRE: {
+               int error;
+               struct alias_data ad = {
+                       .lnk = NULL,
+                       .oaddr = NULL,
+                       .aaddr = NULL,
+                       .aport = NULL,
+                       .sport = NULL,
+                       .dport = NULL,
+                       .maxpktsize = 0
+               };
+               /* Walk out chain. */
+               error = find_handler(OUT, IP, la, pip, &ad);
+               if (error == 0)
+                       iresult = PKT_ALIAS_OK;
+               else
                        iresult = ProtoAliasOut(la, pip,
                            pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
-                       break;
+               break;
                }
-       } else {
-               iresult = FragmentOut(la, pip, &pip->ip_sum);
+       default:
+               iresult = ProtoAliasOut(la, pip,
+                   pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
+               break;
        }
 
+getout_restore:
        SetDefaultAliasAddress(la, addr_save);
 getout:
        return (iresult);

Reply via email to