linux tcp header更改,Linux Netfilter中修改TCP/UDP Payload的方法

来自linux-2.6.36/net/ipv4/netfilter/nf_nat_helper.c

注:该代码可以移植到ebtables中使用,但需要注意struct rtable *rt结构在ebtables中是没有的。

修改UDP payload的代码:

/* Unusual, but possible case. */

static int enlarge_skb(struct sk_buff *skb, unsigned int extra)

{

if (skb->len + extra > 65535)

return 0;

if (pskb_expand_head(skb, 0, extra - skb_tailroom(skb), GFP_ATOMIC))

return 0;

return 1;

}

/* Frobs data inside this packet, which is linear. */

static void mangle_contents(struct sk_buff *skb,

unsigned int dataoff,

unsigned int match_offset,

unsigned int match_len,

const char *rep_buffer,

unsigned int rep_len)

{

unsigned char *data;

BUG_ON(skb_is_nonlinear(skb));

data = skb_network_header(skb) + dataoff;

/* move post-replacement */

memmove(data + match_offset + rep_len,

data + match_offset + match_len,

skb->tail - (skb->network_header + dataoff +

match_offset + match_len));

/* insert data from buffer */

memcpy(data + match_offset, rep_buffer, rep_len);

/* update skb info */

if (rep_len > match_len) {

pr_debug("nf_nat_mangle_packet: Extending packet by "

"%u from %u bytes\n", rep_len - match_len, skb->len);

skb_put(skb, rep_len - match_len);

} else {

pr_debug("nf_nat_mangle_packet: Shrinking packet from "

"%u from %u bytes\n", match_len - rep_len, skb->len);

__skb_trim(skb, skb->len + rep_len - match_len);

}

/* fix IP hdr checksum information */

ip_hdr(skb)->tot_len = htons(skb->len);

ip_send_check(ip_hdr(skb));

}

/* Generic function for mangling variable-length address changes of UDP packet's payload

*

* Takes care about all the nasty sequence number changes, checksumming,

* skb enlargement, ...

*

* match_offset: the payload's start point to be mangled

* match_len: the payload's length to be mangled, when 0 means insert some data into the payload

* rep_buffer: the new data to be inserted.

* rep_len: the new data's length to be inserted.

*/

static int

mangle_udp_packet(struct sk_buff *skb,

unsigned int match_offset,

unsigned int match_len,

const char *rep_buffer,

unsigned int rep_len)

{

struct rtable *rt = skb_rtable(skb);

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;

if (skb->ip_summed != CHECKSUM_PARTIAL) {

if (rt && !(rt->rt_flags & RTCF_LOCAL) &&

skb->dev->features & NETIF_F_V4_CSUM) {

skb->ip_summed = CHECKSUM_PARTIAL;

skb->csum_start = skb_headroom(skb) +

skb_network_offset(skb) +

iph->ihl * 4;

skb->csum_offset = offsetof(struct udphdr, check);

udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,

datalen, IPPROTO_UDP,

0);

} else {

udph->check = 0;

udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,

datalen, IPPROTO_UDP,

csum_partial(udph,

datalen, 0));

if (!udph->check)

udph->check = CSUM_MANGLED_0;

}

} else {

inet_proto_csum_replace2(&udph->check, skb,

htons(oldlen), htons(datalen), 1);

}

return 1;

}

修改TCP payload的方法:

/* Generic function for mangling variable-length address changes inside

* NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX

* command in FTP).

*

* Takes care about all the nasty sequence number changes, checksumming,

* skb enlargement, ...

*

* */

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 rtable *rt = skb_rtable(skb);

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;

if (skb->ip_summed != CHECKSUM_PARTIAL) {

if (!(rt->rt_flags & RTCF_LOCAL) &&

skb->dev->features & NETIF_F_V4_CSUM) {

skb->ip_summed = CHECKSUM_PARTIAL;

skb->csum_start = skb_headroom(skb) +

skb_network_offset(skb) +

iph->ihl * 4;

skb->csum_offset = offsetof(struct tcphdr, check);

tcph->check = ~tcp_v4_check(datalen,

iph->saddr, iph->daddr, 0);

} else {

tcph->check = 0;

tcph->check = tcp_v4_check(datalen,

iph->saddr, iph->daddr,

csum_partial(tcph,

datalen, 0));

}

} else

inet_proto_csum_replace2(&tcph->check, skb,

htons(oldlen), htons(datalen), 1);

if (adjust && rep_len != match_len)

nf_nat_set_seq_adjust(ct, ctinfo, tcph->seq,

(int)rep_len - (int)match_len);

return 1;

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值