java原始套接字打开_原始套接字-IP头包含选项

IP头包含选项

创建原始套接字之后,再打开IP_HDRINCL选项,即可在IP头中封装自己的协议,而不仅仅使用系统预定义的协议。一般可以使用这种方法发送原始UDP和TCP协议,而不是使用系统预定义的协议。一般的,可以使用这种方法来发送原始UDP和TCP数据(win xp sp2已经不支持原始tcp数据的发送了)。这里将介绍如何建立自己的UDP封包,一旦掌握了管理UDP头,即可掌握如何创建自己的协议头,或者封装在IP中的协议头。

对于IPV4来说,堆栈会检查IPV4头中的几个域,例如IPV4标识位就由堆栈设置,如果有必要堆栈将数据块分块。就是说,如果创建了一个原始IPV4封包,设置了IP_HDRINCL发送的封包比MTU大小大,堆栈将把数据分为多块。

当使用这个头包含选项之后,就需要自己在每个发送调用中填写IP头,以及任何封装在里面的协议头。

IP数据报格式

我们称网络层数据报为数据报,IP数据报包含IP头部分和文本部分。IP头有20字节的固定部分和一个长度可变的可选部分。IP头格式如下所示。

3e58e5b0c85724940e8939ee245dd6a8.png

Version域,者四位指定了数据报的IP版本,对IPv4来说,此域值为4

IHL(IP Header Length的缩写),因为IP头的长度不是固定的所以 需要这四位IP数据报中数据部分的开始位置,大多数IP数据报不包含此选项,索引IP数据报有20个字节的头长度。

Type of service(服务器类型TOS)域:包含在IPV4头中,用来区分不同类型的IP数据报

Total length域:这里是IP数据报的总长度,IP头加数据。这个域是16字节长,所以IP数据报大小理论最大值是65535字节,然而数据包很少有超过1500字节的。

Identification域:用来标识以发送的IPV4封包,通常系统每发送一次这个封包就增加一次这个值。

Flags和Fragment offset域:当ipv4封包被分割为较小包时,使用这两个域。DF不要分割,这是给路由器的我一个命令,不要分割数据,主机无法将他们恢复回来。MF代表更多的分割。

Time to live:(生存时间TTL),包含TTL域是为了确保数据报不会永远呆在网络里打圈。每当数据包被路由器处理时,这个域就会减一,减到0这个报文就会被丢弃。

Protocol域:当IP数据报到达目的地时候才使用此域,它指定了数据报的数据部分将要传递给那个传输层协议。6代表要传递给TCP,17代表传递给UDP。

Header checksum域:头校验和帮助路由器检测接收到的IP数据报中的位错误。

Source address和Destination address域:指定此数据报源IP地址和目的IP地址。

Options域:选项域是一个长度可变的域,它包含了可选的信息,最大值是40字节。

为了在数据中包含IP头,下面定义CIPHeader结构

typedef struct _IPHeader//20个字节

{

UCHAR iphVerLen;//版本号和长度

UCHAR ipTos;//服务类型

USHORT ipLength;//封包总长度,既整个数据报的长度

USHORT ipID;//封包标识,唯一标识发送的每一个数据报

USHORT ipFlags;//标志

UCHAR IP TTL;//生存时间TTL

UCHAR ipPROTOCOL;//协议,可能是TCO、UDP、ICMP等

USHORT ipChecksum ;//校验和

ULONG ipSource;//源IP地址

ULONG ipDestination;//目的IP地址

}IPHeader,*PIPHeader;

UDP数据报格式

UDP头仅有八个字节长,包含四个域。

1a495c538c1b2e9ad439c3c5388be539.png

开头两个域分别是源端口号和目的端口号,每个都是16位。第三个域是UDP长度,这是UDP头部和数据报部分的总长。第四个域是校验和,之后就是应用层数据了。

如下定义UDPHeader结构描述UDP头

typedef struct _UDPHeader{

USHORT sourcePort;//源端口号

USHORT destinationPort;//目的端口号

USHORT len;//封包长度

USHORT checksum;//校验和

}UDPHeader,*PUDPHeader;

因为UDP是不可靠连接,所以计算校验和是可选的。和IP的校验和不同,UDP的校验和除了包含UDP节之外,还包含IP头中的几个域。计算UDP校验和所需的额外的域称为伪头,UDP校验和基于如下几个域。

* 32位的源IP地址

* 32位的目的IP地址

* 8位0域

* 8位协议域

* 16位UDP长度

* 16位源端口号

* 16位目的端口号

* 16位UDP长度

* 16位UDP校验和(0)

* UDP载荷

开始的5个域形成了UDP伪头,下面是自定义的UDP登报校验和的例程。

void ComputeUdpPseudoHeaderChecksum(

IPHeader *pIphdr,

UDPHeader *pUdphdr,

char* payload,

int payloadlen

){

char buff[1024];

char* ptr=buff;

int chksumlen=0;

ULONG zero=0;

//包含源ip地址和目的ip地址

memcpy(ptr,&pIphdr->ipSource,sizeof(pIphdr->ipSource));

ptr+=sizeof(pIphdr->ipSource);

chksumlen+=sizeof(pIphdr->ipSource)

memcpy(ptr,&pIphdr->ipDestination,sizeof(pIphdr->ipDestination));

ptr+=sizeof(pIphdr->ipDestination);

chksumlen+=sizeof(pIphdr->ipDestination);

//包含8位0域

memcpy(ptr,&zero,1);

ptr+=1;

chksumlen+=1;

//协议

memcpy(ptr,&pIphdr->ipProtocol,sizeof(pIphdr->ipProtocol));

ptr+=sizeof(pIphdr->ipProtocol);

chksumlen+=sizeof(pIphdr->ipProtocol);

//UDP长度

memcpy(ptr,&pUdphdr->len,sizeof(pUdphdr->len));

ptr+=sizeof(pUdphdr->len);

chksumlen+=sizeof(pUdphdr->len);

//UDP源端口号

memcpy(ptr,&pUdphdr->sourcePort,sizeof(pUdphdr->sourcePort));

ptr+=sizeof(pUdphdr->sourcePort);

chksumlen+=sizeof(pUdphdr->sourcePort);

//UDP目的端口号

memcpy(ptr,&pUdphdr->destinationPort,sizeof(pUdphdr->destinationPort));

ptr+=sizeof(pUdphdr->destinationPort);

chksumlen+=sizeof(pUdphdr->destinationPort);

//又是UDP长度

memcpy(ptr,&pUdphdr->len,sizeof(pUdphdr->len));

ptr+=sizeof(pUdphdr->len);

chksumlen+=sizeof(pUdphdr->len);

//16位的UDP校验和,置为0

memcpy(ptr,&zero,sizeof(USHORT));

ptr+=sizeof(pUdphdr->USHORT);

chksumlen+=sizeof(pUdphdr->USHORT);

//净荷

memcpy(ptr,payload,payloaden);

ptr+=payloaden

chksumlen+=payloaden

//补齐到下一个16位边界

for(int i=0li

*ptr=0;

ptr++;

chksumlen++;

}

pUdphdr->checksum=checksum((USHORT*)buff,chksumlen);//计算这个校验和,将结构填充到UDP头

}

校验和是以字为单位计算的,所以数据的长度如果不是单字倍数的话,需要以0补足。

发送原始UDP封包实例

发送原始UDP封包时,首先要以IPPROTO_UDP为协议类型创建一个原始套接字,打开原始套接字上的IP_HDRINCL选项,然后构建UDP封包,这要先设置IP头在设置UDP头,最后设置UDP净荷数据,初始化完整的UDP封包之后,调用sendto函数即可将他发送。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值