linux 原始套接字实例,Linux 网络编程之原始套接字

1. 介绍

前面主要介绍了流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM),基本上能够满足TCP与UDP的应用。但一些问题,我们仍然无法解决,如:

(1)发送一个自定义的IP包

(2)发送ICMP包

(3)侦听网络上的数据包

(4)伪装IP地址

(5)实现自定义的协议

究其原因,标准的套接字与TCP,UDP层打交道,而原始套接字只与IP层,MAC层打交道。

2.原始套接字的类型

(1)socket(AF_INET,SOCK_RAW,IPPROTO_TCP|IPPROTO_UDP|IPPROTO_ICMP);

(2)socket(PF_PACKET,SOCK_RAW,htons(ETH_P_IP|ETH_P_ARP|ETH_P_RAP|ETH_P_ALL));

第一种套接字类型可得到原始的IP包,这样就可以自己组织TCP,UDP,ICMP包了.

第二种套接字能收到发往本地的MAC帧,也能收到从本机发出去的MAC帧(第3个参数为ETH_P_ALL).也能接收到非发住本地的MAC帧(网卡设置为promisc混杂模式)

ETH_P_IP 0X800 只接收发往本机的mac的ip类型的数据帧

ETH_P_ARP 0X806 只接收发往本机的arp类型的数据帧

ETH_P_RARP 0x8035 只接受发往本机的rarp类型的数据帧

ETH_P_ALL 0X3    接收发往本机的MAC所有类型ip,arp,rarp数据帧,接收从本机发出去的数据帧,混杂模式打开的情况下,会接收到非发往本地的MAC数据帧

此时设备无关的物理地址使用struct sockaddr_ll

所以第二种套接字的功能特别强大.

如果设置了IP_HDRINCL套接字选项,那么需要手动填写IP首部.

3. IP,TCP(首部),UDP(首部),ICMP

IP结构体:

struct iphdr

{

#if __BYTE_ORDER == __LITTLE_ENDIAN

unsigned int ihl:4;

unsigned int version:4;

#elif __BYTE_ORDER == __BIG_ENDIAN

unsigned int version:4; //版本号

unsigned int ihl:4; //首部长度(4字节为单位)

#else

# error "Please fix "

#endif

u_int8_t tos; //服务类型

u_int16_t tot_len; //IP包总长度

u_int16_t id; //标识

u_int16_t frag_off; //是否分片

u_int8_t ttl; //生存时间

u_int8_t protocol; //上层协议

u_int16_t check; //校验和

u_int32_t saddr; //源IP地址

u_int32_t daddr; //目的IP地址

};

UDP首部:

#ifdef __FAVOR_BSD

struct udphdr

{

u_int16_t uh_sport;

u_int16_t uh_dport;

u_int16_t uh_ulen;

u_int16_t uh_sum;

};

else

struct{

u_int16_t source; //源端口

u_int16_t dest; //目的端口

u_int16_t len;  //UDP包的长度

u_int16_t check; //校验和

};

#endif

TCP首部:

struct tcphdr

{

u_int16_t source;   //TCP源端口

u_int16_t dest;      //TCP目的端口

u_int32_t seq;       //序列号

u_int32_t ack_seq;  //确认序列号

# if __BYTE_ORDER == __LITTLE_ENDIAN

u_int16_t res1:4;

u_int16_t doff:4;

u_int16_t fin:1;

u_int16_t syn:1;

u_int16_t rst:1;

u_int16_t psh:1;

u_int16_t ack:1;

u_int16_t urg:1;

u_int16_t res2:2;

# elif __BYTE_ORDER == __BIG_ENDIAN

u_int16_t doff:4;

u_int16_t res1:4;

u_int16_t res2:2;

u_int16_t urg:1;

u_int16_t ack:1;

u_int16_t psh:1;

u_int16_t rst:1;

u_int16_t syn:1; //请求连接标志

u_int16_t fin:1;

# else

#   error "Adjust your defines"

# endif

u_int16_t window;  //滑动窗口的大小

u_int16_t check;   //校验和

u_int16_t urg_ptr;  //紧急字段指针

};

ICMP:

struct icmp

{

u_int8_t  icmp_type;    /* type of message, see below 类型 */

u_int8_t  icmp_code;    /* type sub code 代码*/

u_int16_t icmp_cksum;    /* ones complement checksum of struct校验和 */

union

{

u_char ih_pptr;        /* ICMP_PARAMPROB */

struct in_addr ih_gwaddr;    /* gateway address */

struct ih_idseq        /* echo datagram */

{

u_int16_t icd_id;

u_int16_t icd_seq;

} ih_idseq;

u_int32_t ih_void;

/* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */

struct ih_pmtu

{

u_int16_t ipm_void;

u_int16_t ipm_nextmtu;

} ih_pmtu;

struct ih_rtradv

{

u_int8_t irt_num_addrs;

u_int8_t irt_wpa;

u_int16_t irt_lifetime;

} ih_rtradv;

} icmp_hun;

#define    icmp_pptr    icmp_hun.ih_pptr

#define    icmp_gwaddr    icmp_hun.ih_gwaddr

#define    icmp_id        icmp_hun.ih_idseq.icd_id

#define    icmp_seq    icmp_hun.ih_idseq.icd_seq

#define    icmp_void    icmp_hun.ih_void

#define    icmp_pmvoid    icmp_hun.ih_pmtu.ipm_void

#define    icmp_nextmtu    icmp_hun.ih_pmtu.ipm_nextmtu

#define    icmp_num_addrs    icmp_hun.ih_rtradv.irt_num_addrs

#define    icmp_wpa    icmp_hun.ih_rtradv.irt_wpa

#define    icmp_lifetime    icmp_hun.ih_rtradv.irt_lifetime

union

{

struct

{

u_int32_t its_otime;

u_int32_t its_rtime;

u_int32_t its_ttime;

} id_ts;

struct

{

struct ip idi_ip;

/* options and then 64 bits of data */

} id_ip;

struct icmp_ra_addr id_radv;

u_int32_t   id_mask;

u_int8_t    id_data[1]; //icmp数据

} icmp_dun;

#define    icmp_otime    icmp_dun.id_ts.its_otime

#define    icmp_rtime    icmp_dun.id_ts.its_rtime

#define    icmp_ttime    icmp_dun.id_ts.its_ttime

#define    icmp_ip        icmp_dun.id_ip.idi_ip

#define    icmp_radv    icmp_dun.id_radv

#define    icmp_mask    icmp_dun.id_mask

#define    icmp_data    icmp_dun.id_data

};

IP首部长度为20个字节,TCP首部长度为20个字节,UDP首部长度为8个字节, ICMP的首部长度为8个字节。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值