+From 8ebdc364afd886461d209284ad4c946ac65e6d2b Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Fri, 22 Jan 2021 18:50:43 +0000
+Subject: [PATCH 3/4] Optimise sort_rrset for the case where the RR type no
+ canonicalisation.
+
+Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
+---
+ src/dnssec.c | 69 ++++++++++++++++++++++++++++++++++++----------------
+ 1 file changed, 48 insertions(+), 21 deletions(-)
+
+--- a/src/dnssec.c
++++ b/src/dnssec.c
+@@ -333,37 +333,64 @@ static int sort_rrset(struct dns_header
+ if (!CHECK_LEN(header, state2.ip, plen, rdlen2))
+ return rrsetidx; /* short packet */
+ state2.end = state2.ip + rdlen2;
+-
+- while (1)
++
++ /* If the RR has no names in it then canonicalisation
++ is the identity function and we can compare
++ the RRs directly. If not we compare the
++ canonicalised RRs one byte at a time. */
++ if (*rr_desc == (u16)-1)
+ {
+- int ok1, ok2;
++ int rdmin = rdlen1 > rdlen2 ? rdlen2 : rdlen1;
++ int cmp = memcmp(state1.ip, state2.ip, rdmin);
+
+- ok1 = get_rdata(header, plen, &state1);
+- ok2 = get_rdata(header, plen, &state2);
+-
+- if (!ok1 && !ok2)
++ if (cmp > 0 || (cmp == 0 && rdlen1 > rdmin))
++ {
++ unsigned char *tmp = rrset[i+1];
++ rrset[i+1] = rrset[i];
++ rrset[i] = tmp;
++ swap = 1;
++ }
++ else if (cmp == 0 && (rdlen1 == rdlen2))
+ {
+ /* Two RRs are equal, remove one copy. RFC 4034, para 6.3 */
+ for (j = i+1; j < rrsetidx-1; j++)
+ rrset[j] = rrset[j+1];
+ rrsetidx--;
+ i--;
+- break;
+ }
+- else if (ok1 && (!ok2 || *state1.op > *state2.op))
+- {
+- unsigned char *tmp = rrset[i+1];
+- rrset[i+1] = rrset[i];
+- rrset[i] = tmp;
+- swap = 1;
+- break;
+- }
+- else if (ok2 && (!ok1 || *state2.op > *state1.op))
+- break;
+-
+- /* arrive here when bytes are equal, go round the loop again
+- and compare the next ones. */
+ }
++ else
++ /* Comparing canonicalised RRs, byte-at-a-time. */
++ while (1)
++ {
++ int ok1, ok2;
++
++ ok1 = get_rdata(header, plen, &state1);
++ ok2 = get_rdata(header, plen, &state2);
++
++ if (!ok1 && !ok2)
++ {
++ /* Two RRs are equal, remove one copy. RFC 4034, para 6.3 */
++ for (j = i+1; j < rrsetidx-1; j++)
++ rrset[j] = rrset[j+1];
++ rrsetidx--;
++ i--;
++ break;
++ }
++ else if (ok1 && (!ok2 || *state1.op > *state2.op))
++ {
++ unsigned char *tmp = rrset[i+1];
++ rrset[i+1] = rrset[i];
++ rrset[i] = tmp;
++ swap = 1;
++ break;
++ }
++ else if (ok2 && (!ok1 || *state2.op > *state1.op))
++ break;
++
++ /* arrive here when bytes are equal, go round the loop again
++ and compare the next ones. */
++ }
+ }
+ } while (swap);
+