链路层原始套接字编程-总结
来源:互联网 发布:c语言求逻辑表达式格式 编辑:程序博客网 时间:2024/06/16 05:06
1、链路层原始套接字创建方法:socket(PF_PACKET, SOCK_RAW, htons(protocol)),其中protocal参数为关心的协议类型。
2、默认情况下网卡只处理目的地址是本机网卡地址的包,可通过设置混杂模式,使网卡将收到的所有包(包括组播和广播)都转发给操作系统。代码如下:
struct ifreq ifr;
strcpy(ifr.ifr_name, if_name);
ioctl(fd, SIOCGIFFLAGS, &ifr);
ifr.ifr_flags |= IFF_PROMISC;
ioctl(fd, SIOCSIFFLAGS, &ifr);
3、对于多网卡系统,操作系统在收包时不区分是从哪个网卡收到的,统一转发给用户进程socket,特别的,当用户进程创建了原始套接字socket,那么操作系统在转发消息时,将从网卡收到的buf复制给所有的、关心的原始套接字(原因是操作系统不知道怎么区分不同的原始套接字的包)。
4、可通过bind函数将创建的原始套接字绑定到指定的addr,addr的实际类型为struct sockaddr_ll,绑定时需要设置sll_family,sll_protocol,sll_ifindex这几个参数。其中,sll_ifindex为指定的接口名称的索引,可通过ioctl函数获取ioctl(fd, SIOCGIFINDEX, &ifr);
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
struct sockaddr_ll{
unsigned short int sll_family;
unsigned short int sll_protocol;
int sll_ifindex;
unsigned short int sll_hatype;
unsigned char sll_pkttype;
unsigned char sll_halen;
unsigned char sll_addr[8];
};
5、sendto函数在发送链路层数据时,需要自己组织buf内容,包括以太网头和协议内容。其中dest_addr参数必须设置,与应用层sendto函数指定目的地址不同,链路层发送时需要指定将buf从本机的哪个网卡发送出去。同样,实际类型为struct sockaddr_ll,只需要设置sll_ifindex参数即可。
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
6、recvfrom函数在接收数据时,如果本机的任意一个网卡设置了混杂模式,那么这个函数都能收到链路层包,除非sockfd采用bind函数绑定了网卡。如果绑定的网卡设置了混杂模式,则只能收到发往本网卡包(包括组播包和广播包等)。其中,src_addr为发送包的源地址。
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
7、应用层socket通过(源IP、源端口、目的IP、目的端口)四元组来确定socket对应的进程,操作系统在转发包时能够确定唯一的进程ID;而原始套接字socket没有端口的概念,所以只能通过(源IP、目的IP)或(源MAC、目的MAC)二元组来区分不同的进程。ping程序通过在协议字段里添加进程ID来区分;而Y1731协议里没有设置这个字段的地方。
2、默认情况下网卡只处理目的地址是本机网卡地址的包,可通过设置混杂模式,使网卡将收到的所有包(包括组播和广播)都转发给操作系统。代码如下:
struct ifreq ifr;
strcpy(ifr.ifr_name, if_name);
ioctl(fd, SIOCGIFFLAGS, &ifr);
ifr.ifr_flags |= IFF_PROMISC;
ioctl(fd, SIOCSIFFLAGS, &ifr);
3、对于多网卡系统,操作系统在收包时不区分是从哪个网卡收到的,统一转发给用户进程socket,特别的,当用户进程创建了原始套接字socket,那么操作系统在转发消息时,将从网卡收到的buf复制给所有的、关心的原始套接字(原因是操作系统不知道怎么区分不同的原始套接字的包)。
4、可通过bind函数将创建的原始套接字绑定到指定的addr,addr的实际类型为struct sockaddr_ll,绑定时需要设置sll_family,sll_protocol,sll_ifindex这几个参数。其中,sll_ifindex为指定的接口名称的索引,可通过ioctl函数获取ioctl(fd, SIOCGIFINDEX, &ifr);
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
struct sockaddr_ll{
unsigned short int sll_family;
unsigned short int sll_protocol;
int sll_ifindex;
unsigned short int sll_hatype;
unsigned char sll_pkttype;
unsigned char sll_halen;
unsigned char sll_addr[8];
};
5、sendto函数在发送链路层数据时,需要自己组织buf内容,包括以太网头和协议内容。其中dest_addr参数必须设置,与应用层sendto函数指定目的地址不同,链路层发送时需要指定将buf从本机的哪个网卡发送出去。同样,实际类型为struct sockaddr_ll,只需要设置sll_ifindex参数即可。
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
6、recvfrom函数在接收数据时,如果本机的任意一个网卡设置了混杂模式,那么这个函数都能收到链路层包,除非sockfd采用bind函数绑定了网卡。如果绑定的网卡设置了混杂模式,则只能收到发往本网卡包(包括组播包和广播包等)。其中,src_addr为发送包的源地址。
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
7、应用层socket通过(源IP、源端口、目的IP、目的端口)四元组来确定socket对应的进程,操作系统在转发包时能够确定唯一的进程ID;而原始套接字socket没有端口的概念,所以只能通过(源IP、目的IP)或(源MAC、目的MAC)二元组来区分不同的进程。ping程序通过在协议字段里添加进程ID来区分;而Y1731协议里没有设置这个字段的地方。
0 0
- 链路层原始套接字编程-总结
- 原始套接字编程
- 链路层网络编程技术--原始套接字
- 链路层原始套接字编程-客户端
- 链路层原始套接字编程-服务端
- 网络编程原始套接字
- 原始套接字编程示例
- 网络编程原始套接字
- 原始套接字编程接口
- 基于原始套接字编程
- 原始套接字编程(1)
- 原始套接字学习总结
- 【Linux网络编程】原始套接字编程
- linux原始套接字编程之收发链路层广播(收端)
- Linux网络编程:10. 原始套接字
- WinSocket编程——原始套接字
- 网络编程之-原始套接字
- Linux网络编程:原始套接字
- ORA-00600 [504]
- poj 2299 Ultra-QuickSort(求逆序对)&& poj 1804
- UCHome全面大解析【二】----基本体系结构
- 了解操作系统资源
- 远程调试sqoop代码
- 链路层原始套接字编程-总结
- Android启动预先加载图片
- Android开发全程记录(十四)——Android显示gif动画的方法
- 银行业务调度系统
- BigDecimal类的加减乘除
- 越来越多的理工男与宅男在赚钱是个好现象
- require方法接受以下几种参数的传递:
- a标签的href
- hdu 2206 IP的计算 模拟