原始套接字编程和之前的 UDP 编程差不多,无非就是创建一个套接字后,通过这个套接字接收数据或者发送数据。区别在于,原始套接字可以自行组装数据包(伪装本地 IP,本地 MAC),可以接收本机网卡上所有的数据帧(数据包)。另外,必须在管理员权限下才能使用原始套接字。

 
原始套接字的创建:

int socket ( int family, int type, int protocol );

参数:
  family:协议族 这里写 PF_PACKET
  type:  套接字类,这里写 SOCK_RAW
  protocol:协议类别,指定可以接收或发送的数据包类型,不能写 “0”,取值如下,注意,传参时需要用 htons() 进行字节序转换。

  ETH_P_IP:IPV4数据包
  ETH_P_ARP:ARP数据包
  ETH_P_ALL:任何协议类型的数据包

返回值:
  成功( >0 ):套接字,这里为链路层的套接字
  失败( <0 ):出错

实例如下:

 // 所需头文件
#include <sys/socket.h>
#include <netinet/ether.h>
#include <stdio.h> // perror int main(int argc,char *argv[])
{
int sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL) ); if(sock_raw_fd < ){
perror("socket");
return -;
} return ;
}

获取链路层的数据包:

ssize_t recvfrom( int sockfd,
          void *buf,
          size_t nbytes,
          int flags,
          struct sockaddr *from,
          socklen_t *addrlen );

参数:

  sockfd: 原始套接字
  buf: 接收数据缓冲区
  nbytes: 接收数据缓冲区的大小

  flags: 套接字标志(常为0)

  from: 这里没有用,写 NULL

  addrlen:这里没有用,写 NULL

返回值:
  成功:接收到的字符数
  失败:-1

实例如下:

 #include <stdio.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netinet/ether.h> int main(int argc,char *argv[])
{
unsigned char buf[] = {};
int sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); //获取链路层的数据包
int len = recvfrom(sock_raw_fd, buf, sizeof(buf), , NULL, NULL);
printf("len = %d\n", len); return ;
}

混杂模式

  默认的情况下,我们接收数据,目的地址是本地地址,才会接收。有时候我们想接收所有经过网卡的所有数据流,而不论其目的地址是否是它,这时候我们需要设置网卡为混杂模式

  网卡的混杂模式一般在网络管理员分析网络数据作为网络故障诊断手段时用到,同时这个模式也被网络黑客利用来作为网络数据窃听的入口。在 Linux 操作系统中设置网卡混杂模式时需要管理员权限。在 Windows 操作系统和 Linux 操作系统中都有使用混杂模式的抓包工具,比如著名的开源软件 Wireshark。

通过命令给 Linux 网卡设置混杂模式(需要管理员权限)

设置混杂模式:ifconfig eth0 promisc

取消混杂模式:ifconfig eth0 -promisc

通过代码给 Linux 网卡设置混杂模式

代码如下:

 struct ifreq ethreq;    //网络接口地址

 strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);            //指定网卡名称
if(- == ioctl(sock_raw_fd, SIOCGIFINDEX, &ethreq)) //获取网络接口
{
perror("ioctl");
close(sock_raw_fd);
exit(-);
} ethreq.ifr_flags |= IFF_PROMISC;
if(- == ioctl(sock_raw_fd, SIOCSIFINDEX, &ethreq)) //网卡设置混杂模式
{
perror("ioctl");
close(sock_raw_fd);
exit(-);
}

发送自定义的数据包:

ssize_t sendto( int sockfd,
        const void *buf,
        size_t nbytes,int flags,
        const struct sockaddr *to,
        socklen_t addrlen );

参数:

  sockfd: 原始套接字
  buf: 发送数据缓冲区
  nbytes: 发送数据缓冲区的大小

  flags: 一般为 0
  to: 本机网络接口,指发送的数据应该从本机的哪个网卡出去,而不是以前的目的地址
  addrlen:to 所指向内容的长度

返回值:
  成功:发送数据的字符数
  失败: -1

本机网络接口的定义

发送完整代码如下:

 struct sockaddr_ll sll;                    //原始套接字地址结构
struct ifreq ethreq; //网络接口地址 strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ); //指定网卡名称
if(- == ioctl(sock_raw_fd, SIOCGIFINDEX, ðreq)) //获取网络接口
{
perror("ioctl");
close(sock_raw_fd);
exit(-);
} /*将网络接口赋值给原始套接字地址结构*/
bzero(&sll, sizeof(sll));
sll.sll_ifindex = ethreq.ifr_ifindex; // 发送数据
// send_msg, msg_len 这里还没有定义,模拟一下
int len = sendto(sock_raw_fd, send_msg, msg_len, , (struct sockaddr *)&sll, sizeof(sll));
if(len == -)
{
perror("sendto");
}

这里头文件情况如下:

 #include <net/if.h>// struct ifreq
#include <sys/ioctl.h> // ioctl、SIOCGIFADDR
#include <sys/socket.h> // socket
#include <netinet/ether.h> // ETH_P_ALL
#include <netpacket/packet.h> // struct sockaddr_ll

转自:http://blog.csdn.net/tennysonsky/article/details/44676377

Linux网络编程——原始套接字编程的更多相关文章

  1. Linux网络编程——原始套接字实例:MAC 头部报文分析

    通过<Linux网络编程——原始套接字编程>得知,我们可以通过原始套接字以及 recvfrom( ) 可以获取链路层的数据包,那我们接收的链路层数据包到底长什么样的呢? 链路层封包格式 M ...

  2. Linux Socket 原始套接字编程

    对于linux网络编程来说,可以简单的分为标准套接字编程和原始套接字编程,标准套接字主要就是应用层数据的传输,原始套接字则是可以获得不止是应用层的其他层不同协议的数据.与标准套接字相区别的主要是要开发 ...

  3. UNIX网络编程——原始套接字(dos攻击)

    原始套接字(SOCK_RAW).应用原始套接字,我们可以编写出由TCP和UDP套接字不能够实现的功能. 注意原始套接字只能够由有 root权限的人创建. 可以参考前面的博客<<UNIX网络 ...

  4. UNIX网络编程——原始套接字的魔力【续】

    如何从链路层直接发送数据帧 上一篇里面提到的是从链路层"收发"数据,该篇是从链路层发送数据帧. 上一节我们主要研究了如何从链路层直接接收数据帧,可以通过bind函数来将原始套接字绑 ...

  5. UNIX网络编程——原始套接字的魔力【上】

    基于原始套接字编程 在开发面向连接的TCP和面向无连接的UDP程序时,我们所关心的核心问题在于数据收发层面,数据的传输特性由TCP或UDP来保证: 也就是说,对于TCP或UDP的程序开发,焦点在Dat ...

  6. Linux网络编程——原始套接字能干什么?

    通常情况下程序员接所接触到的套接字(Socket)为两类: (1)流式套接字(SOCK_STREAM):一种面向连接的 Socket,针对于面向连接的TCP 服务应用: (2)数据报式套接字(SOCK ...

  7. LINUX 网络编程 原始套接字

    一 原始套接字 原始套接字(SOCK_RAW)是一种不同于SOCK_STREAM.SOCK_DGRAM的套接字,它实现于系统核心.然而,原始套接字能做什么呢?首先来说,普通的套接字无法处理ICMP.I ...

  8. 关于linux 原始套接字编程

    关于linux 网络编程最权威的书是<<unix网络编程>>,但是看这本书时有些内容你可能理解的不是很深刻,或者说只知其然而不知其所以然,那么如果你想搞懂的话那么我建议你可以看 ...

  9. UNIX网络编程——原始套接字SOCK_RAW

    实际上,我们常用的网络编程都是在应用层的报文的收发操作,也就是大多数程序员接触到的流式套接字(SOCK_STREAM)和数据包式套接字(SOCK_DGRAM).而这些数据包都是由系统提供的协议栈实现, ...

随机推荐

  1. Android 内存监测工具

    本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 文/幻影浪子 [博主导读]俗话说:工欲善其事必先利其器!我们先来了解下内存监测工具是怎么使用的?为内 ...

  2. GestureDetector-onfling不执行

    今天在做计算器的时候,遇到了一个问题,就是当我使用GestureDetector的时候,onFling方法不执行,而其他的可以执行.代码如下 @Override public boolean onDo ...

  3. JavaScript 倒计时器,闹钟功能

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  4. 洛谷 P1644 跳马问题

    P1644 跳马问题 题目背景 在爱与愁的故事第一弹第三章出来前先练练四道基本的回溯/搜索题吧…… 题目描述 中国象棋半张棋盘如图1所示.马自左下角(0,0)向右上角(m,n)跳.规定只能往右跳,不准 ...

  5. 忍者无敌-实例解说Cocos2d-x瓦片地图

    实例比較简单,如图所看到的,地图上有一个忍者精灵,玩家点击他周围的上.下.左.右,他能够向这个方向行走. 当他遇到障碍物后是无法穿越的,障碍物是除了草地以为部分,包含了:树.山.河流等. 忍者实例地图 ...

  6. LeetCode Algorithm 05_Longest Palindromic Substring

    Given a string S, find the longest palindromic substring in S. You may assume that the maximum lengt ...

  7. 如何在anaconda中切换python2

    如果你不切换可能是默认的python3环境. 下面是在python27版本下下载qt5

  8. JQ实现选项卡(jQuery原型插件扩展)

    下边分为两个版本,一种是点击切换选项(index.js),一种是滑过切换选项(index1.js) HTML文件: jq使用jquery-1.11.3.js版本 <!DOCTYPE html&g ...

  9. [React Intl] Format Numbers with Separators and Currency Symbols using react-intl FormattedNumber

    Using a react-intl FormattedNumber component, we'll pass a Number and a few additional props in orde ...

  10. Redis学习笔记(六)---List

    1.ArrayList与LinkList的区别 ArrayList的使用数组存入的方式,所以根据索引查询数据速度快,而增删元素是比较慢的,它需要将数据一位一位的移动,知道达到要求. LinkList使 ...