现在的位置: 首页 > 综合 > 正文

mstpscap分析之先行知识

2013年08月27日 ⁄ 综合 ⁄ 共 4767字 ⁄ 字号 评论关闭

1socket编程

Packet套接字用于在MAC层上收发原始数据帧,这样就允许用户在用户空间完成MAC之上各个层次的实现。给无论是进行开发还是测试的人们带来了极大的便利性。

Packet套接字的定义方式与传送层的套接字定义类似,如下:

packet_socket=socket(PF_PACKET,int socket_type,int protocol);

(这个套接字的打开需要用户有root权限)

其中socket_type有两种类型,一种为SOCK_RAW,它是包含了MAC层头部信息的原始分组,当然这种类型的套接字在发送的时候需要自己加上一个MAC头部(其类型定义在linux/if_ether.h中,ethhdr),另一种是SOCK_DGRAM类型,它是已经进行了MAC层头部处理的,即收上的帧已经去掉了头部,而发送时也无须用户添加头部字段。

Protocol是指其送交的上层的协议号,如IP0x0800,当其为htons(ETH_P_ALL)(其宏定义为0)时表示收发所有的协议。

创建好套接字后,就可以通过与UDP一样的recvfromsendto函数进行数据的收发,其目的地址结构为sockaddr_ll,这与传送层的地址结构定义是不一样的,其长度为20字节(在TCP/IP的链路层地址中使用了18字节),而传送层的地址结构长度为16字节。

Sockaddr_ll结构如下:

struct sockaddr_ll

{

unsigned short sll_family; /*总是 AF_PACKET */

unsigned short sll_protocol; /*物理层的协议 */

int sll_ifindex; /* 接口号 */

unsigned short sll_hatype; /*报头类型 */

unsigned char sll_pkttype; /*分组类型 */

unsigned char sll_halen; /*
地址长度 */

unsigned char sll_addr[8]; /*物理层地址 */

};

sll_protocol 是在 linux/if_ether.h头文件中定义的按网络层排序的标准的以太桢协议类型。sll_ifindex
是接口的索引号(参见netdevice(2))0匹配所有的接口(当然只有合法的才用于绑定)
sll_hatype
是在 linux/if_arp.h 中定义的 ARP硬件地址类型。 sll_pkttype
包含分组类型。有效的分组类型是:目标地址是本地主机的分组用的 PACKET_HOST,物理层广播分组用的 PACKET_BROADCAST,发送到一个物理层多路广播地址的分组用的 PACKET_MULTICAST,在混杂(promiscuous)模式下的设备驱动器发向其他主机的分组用的
PACKET_OTHERHOST
,本源于本地主机的分组被环回到分组套接口用的 PACKET_OUTGOING。这些类型只对接收到的分组有意义。sll_addr sll_halen
包括物理层(例如 IEEE 802.3)地址和地址长度。精确的解释依赖于设备。(本段引于packet的用户手册)

当在多个网络接口的主机上使用这个套接字时,若要指定接收或发送的接口时可以使用bind进行绑定,这与TCP套接字的操作一样,但其内涵并不相同。绑定时将根据地址结构中的sll_protocalsll_ifindex分别绑定收发的协议号和接口索引号,接口索引号sll_ifindex0时表示使用有效的所有接口。接口的sll_ifindex值可以通过ioctl获得,如下面是获得名字为“eth0”的接口的索引号

       strcpy(ifr.ifr_name,"eth0");

       ioctl(fd_packet,SIOCGIFINDEX,&ifr);

取得的值保存在ifr结构体的ifr_ifindex中,ifr结构类型为“struct ifreq

BTW,要获得接口的物理地址同样使用ioctl可以得到

ioctl(fd_packet,SIOCGIFHWADDR,&ifr);

以数据形式保存在ifrifr_hwaddr.sa_data中。

另外需要注意的是,在调用recvfrom函数时返回的地址长度信息为18字节,原因是在sockaddr_ll结构中的sll_addr[8]8字节,MAC地址只使用了其中的前6字节。在用sendto发送时需要将目的地址结构体强制转换为struct
sockaddr
类型,而且指定的长度必须为20字节,而不能是18或其它值。

我在使用中当指定了协议类型后可以准备接收该类型的数据帧,但有个问题一直困扰着我,就是无法过滤掉广播帧,必须要收到帧后判断目的地址是否为自己,然后如果用SOCK_DGRAM的时候又如何判断呢?本人正在探索中,一旦有新进展将第一时间与大家分享。

 

/*PF_PACKET接口可以操作链路层的数据。

isock = socket(PF_PACKET, SOCK_DGRAM, 0) //0,之后会用setsockopt之类的设置

第二个参数,在使用SOCK_RAW, SOCK_DGRAMSOCK_PACKET的区别:

(1)使用SOCK_RAW发送的数据必须包含链路层的协议头,接受得到的数据包,包含链路层协议头。而使用SOCK_DGRAM则都不含链路层的协议头。

(2)SOCK_PACKET也是可以使用的,但是已经废弃,以后不保证还能支持,不推荐使用。

(3)在使用SOCK_RAWSOCK_DGRAMSOCK_PACKET时,在sendtorecvfrom中使用的地址类型不同,前两者使用sockaddr_ll类型的地址,

而后者使用sockaddr类型的地址。

(4)socket的第一个参数使用PF_INET,第二个参数使用SOCK_RAW,则可以得到原始的IP包。*/

 

2htons函数

  uint16_t htons(uint16_t hostshort);

  htons的功能:将一个无符号短整型数值转换为网络字节序,即大端模式(big-endian)

  参数u_short hostshort: 16位无符号整数

返回值:TCP / IP网络字节顺序.

3struct
ifreq 
 
获取IP mac

struct   ifreq   {

        char         ifr_name[IFNAMSIZ];   

        union   {

                struct     sockaddr   ifru_addr;

                struct     sockaddr   ifru_dstaddr;

                struct     sockaddr   ifru_broadaddr;

                short      ifru_flags;

                int        ifru_metric;

                caddr_t    ifru_data;

        }   ifr_ifru;

};

4strncpy函数

原型:char * strncpy(char *dest, char *src, size_t n);

  功能:将字符串src中最多n个字符复制到字符数组dest(它并不像strcpy一样只有遇到NULL才停止复制,而是多了一个条件停止,就是说如果复制到第n个字符还未遇到NULL,也一样停止),返回指向dest的指针。

5sockaddr_ll是设备无关的物理层地址

struct sockaddr_ll {

unsigned short sll_family; /*总是 AF_PACKETPACKETPACKETPACKET */

unsigned short sll_protocol; /*物理层的协议 */

int sll_ifindex; /* 接口号 */

unsigned short sll_hatype; /*报头类型 */

unsigned char sll_pkttype; /*分组类型 */

unsigned char sll_halen; /*
地址长度 */

unsigned char sll_addr[8]; /*物理层地址 */

};

sll_protocol 是在 linuxlinuxlinuxlinux/if_ether.h头文件中定义的按网络层排序的标准的以太桢协议类型。sll_ifindex
是接口的索引号(参见 netdevice(2))0匹配所有的接口(当然只有合法的才用于绑定)
sll_hatype
是在 linuxlinuxlinuxlinux/if_arp.h
中定义的 ARP 硬件地址类型。 sll_pkttype包含分组类型。有效的分组类型是:目标地址是本地主机的分组用的 PACKETPACKETPACKETPACKET_HOST,物理层广播分组用的
PACKETPACKETPACKETPACKET_BROADCAST
,发送到一个物理层多路广播地址的分组用的 PACKETPACKETPACKETPACKET_MULTICAST,在混杂(promiscuous)模式下的设备驱动器发向其他主机的分组用的 PACKETPACKETPACKETPACKET_OTHERHOST,本源于本地主机的分组被环回到分组套接口用的
PACKETPACKETPACKETPACKET_OUTGOING
。这些类型只对接收到的分组有意义。sll_addr sll_halen
包括物理层(例如 IEEE 802.3)地址和地址长度。精确的解释依赖于设备。};

6SNAP

Ethernet SNAP协议是IEEE为保证在802.2 LLC上支持更多的上层协议的同时更好地支持IP协议而发布的标准,与802.3/802.2
LLC
一样802.3/802.2 SNAP也带有LLC头,但是扩展了LLC属性,新添加了一个2字节的协议类型域(同时将SAP的值置为AA),从而使其可以标识更多的上层协议类型;另外添加了一个3字节的厂商代码字段用于标记不同的组织。RFC
1042
定义了IP报文在802.2网络中的封装方法和ARP协议在802.2 SANP中的实现方法。

7Linux下的signal函数

signal信号函数,第一个参数表示需要处理的信号值(SIGHUP),第二个参数为处理函数或者是一个表示,这里,SIG_IGN表示忽略SIGHUP那个注册的信号。

功能:设置某一信号的对应动作  

函数原型:

void (*signal(int signum,void(* handler)(int)))(int);  

或者:typedef void(*sig_t) ( int );  sig_t signal(int signum,sig_t han

8strtol函数

long int strtol(const char *nptr,char **endptr,int base);

这个函数会将参数nptr字符串根据参数base来转换成长整型数。参数base范围从236,或0。参数base代表采用的进制方式,如base值为10则采用10进制,若base值为16则采用16进制等。当base值为0时则是采用10进制做转换,但遇到如’0x’前置字符则会使用16进制做转换、遇到’0’前置字符而不是’0x’的时候会使用8进制做转换。一开始strtol()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,再遇到非数字或字符串结束时('\0')结束转换,并将结果返回。若参数endptr不为NULL,则会将遇到不合条件而终止的nptr中的字符指针由endptr返回;若参数endptrNULL,则会不返回非法字符串。

抱歉!评论已关闭.