最近遇到这样的一个问题:
在router背后有2台pc,通过dhcprelay的方式从外面的dhcpserver获取ip地址。
问题描述:
但是当地址租期到一定的时间后,两台pc会去发单播包续自己的ip地址。但是server回这些单播地址的时候,会把ack包回给第一台机器。第二台机器续包不成功之后,会发广播包出去,被router上面的dhcprelay进程处理,然后从外面的dhcpserver获得ip地址。该问题不影响功能使用
问题原因:
因为单播包,这两台pc建立了连线记录,期望relay的包的记录是一样的,所以这样会产生,这些relay会来的包都匹配了第一条连线记录,所以ack没有回到第二台机器。
解决办法:
为简单起见,可以扩展udp的连线记录字段,dhcp包有一个id字段是唯一的,在udp记录中增加id。
ip_conntrack_tuple结构体添加一个int变量xid。
+++ ip_conntrack_proto_udp.c 2009-10-13 14:23:09.000000000 +0800
@@ -5,6 +5,14 @@
#include <linux/in.h>
#include <linux/udp.h>
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
+struct bootp_hdr { /* BOOTP packet format */
+ u8 op; /* 1=request, 2=reply */
+ u8 htype; /* HW address type */
+ u8 hlen; /* HW address length */
+ u8 hops; /* Used only by gateways */
+ u32 xid; /* Transaction ID */
+ char *other;
+};
@@ -15,6 +23,7 @@ static int udp_pkt_to_tuple(const void *
{
const struct udphdr *hdr = datah;
+ struct bootp_hdr *bootp_h = (void *)hdr + 8;
+ if((ntohs(hdr->source) == 68)||(ntohs(hdr->dest) == 67)||(ntohs(hdr->source)==67)||(ntohs(hdr->dest)==68))
+ {
+ printk("in the %s the source port %d dest port %d./n",__FUNCTION__,ntohs(hdr->source),ntohs(hdr->dest));
+ if(NULL == bootp_h)
+ tuple->dst.u.udp.xid = 0;
+ else
+ tuple->dst.u.udp.xid = (unsigned int)(bootp_h->xid);
tuple->dst.u.udp.xid = orig->dst.u.udp.xid;
最后测试成功。