linux内核丢弃udp报文,内核udp报文截取、修改和发送
近來(lái)做一個(gè)產(chǎn)品需要在網(wǎng)關(guān)上獲取特定UDP端口(假設(shè)是1000端口)的報(bào)文,并將其轉(zhuǎn)發(fā)給其它設(shè)備的1000端口。雖然此類文章網(wǎng)上已經(jīng)有很多了,但我還是貼上來(lái),這樣自己也做下記錄,大家也多一份參考。
下面只給出了代碼片段,自己慢慢調(diào)試。
我們假設(shè)網(wǎng)絡(luò)拓?fù)淙缦滤?#xff1a;
LINUX
--------- --------- ---------
| PC-1 |-------| Server | -------| DataSrv |
--------- --------- ---------
pc-1發(fā)送udp報(bào)文到server的1000端口時(shí),我們將報(bào)文拷貝一份并發(fā)送給DataSrv的1000端口。
報(bào)文的獲取,我們采用netfilter hook. 我們將hook鉤到 NF_IP_LOCAL_IN,優(yōu)先級(jí)別設(shè)置成NF_IP_PRI_FIRST。
為什么hook到NF_IP_LOCAL_IN 而不是PERROUTING呢? 這是因?yàn)閔ook到 LOCAL_IN的話,我們就不用去考慮報(bào)文的重組了。如下圖:
ip_rcv ------> ip_local_deliver ----------> netfilter
|-----------ip_defrag-------^
為什么優(yōu)先級(jí)別設(shè)置成最高了,這樣可以防止udp的穿透。
這里我們不詳細(xì)描述netfilter hook如何編寫(xiě)。下面我們來(lái)看獲取到skb(重組好了的)的報(bào)文后,我們?nèi)绾翁幚怼?/p>
首先,我們假設(shè)DataSrv的ip地址為 192.168.1.254/24;Server的ip地址為 192.168.1.253/24。
#define TEST_XMIT(skb, rt) \
NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, (skb), NULL, \
(rt)->u.dst.dev, dst_output);
#define IP_PARTS_NATIVE(n) \
(unsigned int)((n)&0xFF), \
(unsigned int)((n)>>8)&0xFF, \
(unsigned int)((n)>>16)&0xFF, \
(unsigned int)((n)>>24)&0xFF
#define TEST_BUG() BUG()
#define TEST_ERR(msg...) printk(KERN_ERR "TEST: " msg)
#define TEST_INFO(msg...) printk(KERN_INFO "TEST: " msg)
#define TEST_WARNING(msg...) printk(KERN_WARNING "TEST: " msg)
#define TEST_ERR_RL(msg...) \
do { \
if (net_ratelimit()) \
printk(KERN_ERR "TEST: " msg); \
} while (0)
//調(diào)用test_pop前 需要 拷貝或克隆 skb,然后再傳入
static inline int TEST_pop (struct sk_buff * skb)
{
struct iphdr * iph = NULL;
struct rtable * rt = NULL;
struct ethhdr * ethh = NULL;
struct flowi fl;
unsigned long ulpeerip = 0;
unsigned int udphoff = 0;
fl.oif = 0;
fl.nl_u.ip4_u.daddr = in_aton ("192.168.1.254");
fl.nl_u.ip4_u.saddr = in_aton ("192.168.1.253");
fl.nl_u.ip4_u.tos = RT_TOS(0);
//查找出口路由
if (unlikely (ip_route_output_key(&rt, &fl))) {
TEST_ERR("%s no route from 192.168.1.253 to 192.168.1.254 (%s:%d)\n",
__FUNCTION__, __FILE__, __LINE__);
return (1);
}
//修改IP頭
iph = skb->nh.iph;
iph->saddr = in_aton ("192.168.1.253");//sip;
iph->daddr = in_aton ("192.168.1.254");
//ip地址改變,需要重新計(jì)算udp校驗(yàn)和
udph = (struct udphdr*) (skb->data iph->ihl * 4);
udphoff = iph->ihl * 4;
skb->csum = 0;
skb->csum = skb_checksum (skb, udphoff, skb->len - udphoff, 0);
udph->check = csum_tcpudp_magic (iph->saddr, iph->daddr,
skb->len - udphoff,
IPPROTO_UDP,
skb->csum);
//獲取ip序號(hào)
ip_select_ident(iph, &rt->u.dst, NULL);
//重新計(jì)算ip頭校驗(yàn)和
ip_send_check(iph);
//重新設(shè)置路有入口
dst_release(skb->dst);
skb->dst = &rt->u.dst;
//清除netfilter信息
nf_reset (skb);
//發(fā)送
TEST_XMIT (skb, rt);
return (0);
}
閱讀(893) | 評(píng)論(1) | 轉(zhuǎn)發(fā)(0) |
總結(jié)
以上是生活随笔為你收集整理的linux内核丢弃udp报文,内核udp报文截取、修改和发送的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: bernoulli_Python-Ber
- 下一篇: Linux 设置多指触控手势,以 Man