/* Generic function for mangling variable-length address changes inside * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX * command in the Amanda protocol) * * Takes care about all the nasty sequence number changes, checksumming, * skb enlargement, ... * * XXX - This function could be merged with nf_nat_mangle_tcp_packet which * should be fairly easy to do. */ int nf_nat_mangle_udp_packet(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned int match_offset, unsigned int match_len, const char *rep_buffer, unsigned int rep_len) { struct iphdr *iph; struct udphdr *udph; int datalen, oldlen; /* UDP helpers might accidentally mangle the wrong packet */ iph = ip_hdr(skb); if (skb->len < iph->ihl*4 + sizeof(*udph) + match_offset + match_len) return 0; if (!skb_make_writable(skb, skb->len)) return 0; if (rep_len > match_len && rep_len - match_len > skb_tailroom(skb) && !enlarge_skb(skb, rep_len - match_len)) return 0; iph = ip_hdr(skb); udph = (void *)iph + iph->ihl*4; oldlen = skb->len - iph->ihl*4; mangle_contents(skb, iph->ihl*4 + sizeof(*udph), match_offset, match_len, rep_buffer, rep_len); /* update the length of the UDP packet */ datalen = skb->len - iph->ihl*4; udph->len = htons(datalen); /* fix udp checksum if udp checksum was previously calculated */ if (!udph->check && skb->ip_summed != CHECKSUM_PARTIAL) return 1; nf_nat_csum(skb, iph, udph, datalen, &udph->check, oldlen); return 1; }
int nf_nat_mangle_udp_packet(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned int match_offset, unsigned int match_len, const char *rep_buffer, unsigned int rep_len) { struct iphdr *iph; struct udphdr *udph; int datalen, oldlen; if (!skb_make_writable(skb, skb->len)) return 0; if (rep_len > match_len && rep_len - match_len > skb_tailroom(skb) && !enlarge_skb(skb, rep_len - match_len)) return 0; iph = ip_hdr(skb); udph = (void *)iph + iph->ihl*4; oldlen = skb->len - iph->ihl*4; mangle_contents(skb, iph->ihl*4 + sizeof(*udph), match_offset, match_len, rep_buffer, rep_len); datalen = skb->len - iph->ihl*4; udph->len = htons(datalen); if (!udph->check && skb->ip_summed != CHECKSUM_PARTIAL) return 1; nf_nat_csum(skb, iph, udph, datalen, &udph->check, oldlen); return 1; }
int __nf_nat_mangle_tcp_packet(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned int match_offset, unsigned int match_len, const char *rep_buffer, unsigned int rep_len, bool adjust) { struct iphdr *iph; struct tcphdr *tcph; int oldlen, datalen; if (!skb_make_writable(skb, skb->len)) return 0; if (rep_len > match_len && rep_len - match_len > skb_tailroom(skb) && !enlarge_skb(skb, rep_len - match_len)) return 0; SKB_LINEAR_ASSERT(skb); iph = ip_hdr(skb); tcph = (void *)iph + iph->ihl*4; oldlen = skb->len - iph->ihl*4; mangle_contents(skb, iph->ihl*4 + tcph->doff*4, match_offset, match_len, rep_buffer, rep_len); datalen = skb->len - iph->ihl*4; nf_nat_csum(skb, iph, tcph, datalen, &tcph->check, oldlen); if (adjust && rep_len != match_len) nf_nat_set_seq_adjust(ct, ctinfo, tcph->seq, (int)rep_len - (int)match_len); return 1; }