docs: def zero_mutable_fields(pkt, sending=False):
      """
      When using AH, all "mutable" fields must be "zeroed" before calculating
      the ICV. See RFC 4302, Section 3.3.3.1. Handling Mutable Fields.
  
      @param pkt: an IP(v6) packet containing an AH layer.
                  NOTE: The packet will be modified
      @param sending: if true, ipv6 routing headers will not be reordered
      """
  
      if pkt.haslayer(AH):
          pkt[AH].icv = chr(0) * len(pkt[AH].icv)
      else:
          raise TypeError('no AH layer found')
  
      if pkt.version == 4:
          # the tos field has been replaced by DSCP and ECN
          # Routers may rewrite the DS field as needed to provide a
          # desired local or end-to-end service
          pkt.tos = 0
          # an intermediate router might set the DF bit, even if the source
          # did not select it.
          pkt.flags = 0
          # changed en route as a normal course of processing by routers
          pkt.ttl = 0
          # will change if any of these other fields change
          pkt.chksum = 0
  
          immutable_opts = []
          for opt in pkt.options:
              if opt.option in IMMUTABLE_IPV4_OPTIONS:
                  immutable_opts.append(opt)
              else:
                  immutable_opts.append(Raw(chr(0) * len(opt)))
          pkt.options = immutable_opts
  
      else:
          # holds DSCP and ECN
          pkt.tc = 0
          # The flow label described in AHv1 was mutable, and in RFC 2460 [DH98]
          # was potentially mutable. To retain compatibility with existing AH
          # implementations, the flow label is not included in the ICV in AHv2.
          pkt.fl = 0
          # same as ttl
          pkt.hlim = 0
  
          next_hdr = pkt.payload
  
          while isinstance(next_hdr, (IPv6ExtHdrHopByHop, IPv6ExtHdrRouting, IPv6ExtHdrDestOpt)):
              if isinstance(next_hdr, (IPv6ExtHdrHopByHop, IPv6ExtHdrDestOpt)):
                  for opt in next_hdr.options:
                      if opt.otype & 0x20:
                          # option data can change en-route and must be zeroed
                          opt.optdata = chr(0) * opt.optlen
              elif isinstance(next_hdr, IPv6ExtHdrRouting) and sending:
                  # The sender must order the field so that it appears as it
                  # will at the receiver, prior to performing the ICV computation.
                  next_hdr.segleft = 0
                  if next_hdr.addresses:
                      final = next_hdr.addresses.pop()
                      next_hdr.addresses.insert(0, pkt.dst)
                      pkt.dst = final
              else:
                  break
  
              next_hdr = next_hdr.payload
  
      return pkt