原始套接字

在计算机网络中, 原始套接字（raw socket）是一种网络套接字，允许直接发送/接收IP协议数据包而不需要任何传输层协议格式。

**简介**
对于标准的套接字，通常数据按照选定的传输层协议(例如TCP、UDP)自动封装，socket用户并不知道在网络介质上广播的数据包含了这种协议包头。
从原始套接字读取数据包含了传输层协议包头。用原始套接字发送数据，是否自动增加传输层协议包头是可选的。
原始套接字用于安全相关的应用程序，如nmap。原始套接字一种可能的用例是在用户空间实现新的传输层协议。 原始套接字常在网络设备上用于路由协议，例如IGMPv4、开放式最短路径优先协议 (OSPF)、互联网控制消息协议 (ICMP)。Ping就是发送一个ICMP响应请求包然后接收ICMP响应回复.

**实现**
大部分套接字API都支持原始套接字功能。Winsock自2001年起在Windows XP上支持原始套接字。但由于安全原因，2004年微软限制了Winsock的原始套接字功能。
Ian Griffiths for IanG on Tap. 12 August, 2004.  Raw Sockets Gone in XP SP2 date=20210209131912 

**例子**
下例在Linux上实现了Ping程序的主要功能：
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
/* 校验和计算 */
u_int16_t checksum(unsigned short *buf, int size)
{
	unsigned long sum = 0;
	while (size > 1) {
		sum += *buf;
		buf++;
		size -= 2;
	}
	if (size == 1)
		sum += *(unsigned char *)buf;
	sum = (sum & 0xffff) + (sum >> 16);
	sum = (sum & 0xffff) + (sum >> 16);
	return ~sum;
}
/* protocol指定的raw socket创建 */
int make_raw_socket(int protocol)
{
	int s = socket(AF_INET, SOCK_RAW, protocol);
	if (s type = type;
	icmphdr->code = code;
	icmphdr->checksum = 0;
	icmphdr->un.echo.id = id;
	icmphdr->un.echo.sequence = seq;
	icmphdr->checksum = checksum((unsigned short *)icmphdr, sizeof(struct icmphdr));
}
int main(int argc, char **argv)
{
	int n, soc;
	char buf1500;
	struct sockaddr_in addr;
	struct in_addr insaddr;
	struct icmphdr icmphdr;
	struct iphdr *recv_iphdr;
	struct icmphdr *recv_icmphdr;
	if (argc ihl saddr;
	/* 检查送信包的源地址匹配受信包的目的地址  */
	if (!strcmp(argv1, inet_ntoa(insaddr)) && recv_icmphdr->type == ICMP_ECHOREPLY)
		printf("icmp echo reply from %s\n", argv1);
	close(soc);
	return 0;
}
下例是binding一个原始套接字并使用：
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define PACKET_LENGTH	1024

int CreateRawSocket(int protocol_to_sniff)
{
	int rawsock;
	if((rawsock = socket(PF_PACKET, SOCK_RAW, htons(protocol_to_sniff)))== -1) {
		perror("Error creating raw socket: ");
		exit(-1);
	}
	return rawsock;
}

int BindRawSocketToInterface(char *device, int rawsock, int protocol)
{
	struct sockaddr_ll sll;
	struct ifreq ifr;
	memset(&sll, 0, sizeof(sll));
	memset(&ifr, 0, sizeof(ifr));
	/* First Get the Interface Index  */
	strncpy((char *)ifr.ifr_name, device, IFNAMSIZ);
	if((ioctl(rawsock, SIOCGIFINDEX, &ifr)) == -1) {
		printf("Error getting Interface index !\n");
		exit(-1);
	}
	/* Bind our raw socket to this interface */
	sll.sll_family = AF_PACKET;
	sll.sll_ifindex = ifr.ifr_ifindex;
	sll.sll_protocol = htons(protocol);
	if((bind(rawsock, (struct sockaddr *)&sll, sizeof(sll)))== -1) {
		perror("Error binding raw socket to interface\n");
		exit(-1);
	}
	return 1;
}

int SendRawPacket(int rawsock, unsigned char *pkt, int pkt_len)
{
	int sent= 0;
	/* A simple write on the socket ..thats all it takes ! */
	if((sent = write(rawsock, pkt, pkt_len)) != pkt_len) {
		return 0;
	}
	return 1;
}
/* argv1 is the device e.g. eth0
argv2 is the number of packets to send */

main(int argc, char **argv)
{
	int raw;
	unsigned char packetPACKET_LENGTH;
	int num_of_pkts;
	/* Set the packet to all A's */
	memset(packet, 'A', PACKET_LENGTH);
	/* Create the raw socket */
	raw = CreateRawSocket(ETH_P_ALL);
	/* Bind raw socket to interface */
	BindRawSocketToInterface(argv1, raw, ETH_P_ALL);
	num_of_pkts = atoi(argv2);
	while((num_of_pkts--)>0) {
		if(!SendRawPacket(raw, packet, PACKET_LENGTH)) {
			perror("Error sending packet");
		} else {
			printf("Packet sent successfully\n");
		}
	}
	close(raw);
	return 0;
}

**参见**
 IPv4包格式- IPv6包格式

**参考文献**

**外部链接**
  Net::RawIP; module for Perl applications. Created by  Sergey Kolychev.- Network Programming for Microsoft Windows (ISBN 0-7356-1579-9)-  A little more info on raw sockets and Windows XP SP2 - Michael Howard's Web Log an indication of what's actually allowed on Windows.-  SOCK_RAW Demystified: article describing inner workings of Raw Sockets date=20210224165542 - C language examples of Linux raw sockets for IPv4 and IPv6 - David Buchan's C language examples of IPv4 and IPv6 raw sockets for Linux.