/* This is the interesting part of the code. */
static unsigned int
ip6t_addrh_target(struct sk_buff **pskb, const struct net_device *in,
                const struct net_device *out, unsigned int hooknum,
                const void *targinfo, void *userinfo)
{
  struct ipv6hdr *iph;
  const struct ip6t_ADDRH_info *info = targinfo;
  /* info:     struct ip6t_ADDRH_info { struct in6_addr target; }; */

  iph = (*pskb)->nh.ipv6h;

  printk(...iph->daddr...); //prints packet info for debugging

  /* with the line below, the packet doesn't change. Without the line, it gets dropped. */
  //if (!skb_ip_make_writable(pskb, sizeof(struct ipv6hdr))) return NF_DROP;

  iph->daddr = info->target;

  (*pskb)->nfcache |= NFC_ALTERED; 

  printk(...iph->daddr...); //prints packet info for debugging (the change can always be seen here)

  return IP6T_CONTINUE;
}
