原始套接字在计算机网络中, 原始套接字(raw socket)是一种网络套接字,允许直接发送/接收IP协议数据包而不需要任何传输层协议格式。 简介对于标准的套接字,通常数据按照选定的传输层协议(例如TCP、UDP)自动封装,socket用户并不知道在网络介质上广播的数据包含了这种协议包头。 从原始套接字读取数据包含了传输层协议包头。用原始套接字发送数据,是否自动增加传输层协议包头是可选的。 原始套接字用于安全相关的应用程序,如nmap。原始套接字一种可能的用例是在用户空间实现新的传输层协议。[1] 原始套接字常在网络设备上用于路由协议,例如IGMPv4、开放式最短路径优先协议 (OSPF)、互联网控制消息协议 (ICMP)。Ping就是发送一个ICMP响应请求包然后接收ICMP响应回复.[2] 实现大部分套接字API都支持原始套接字功能。Winsock自2001年起在Windows XP上支持原始套接字。但由于安全原因,2004年微软限制了Winsock的原始套接字功能。[3] 例子下例在Linux上实现了Ping程序的主要功能: #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>
#include <netdb.h>
/* 校验和計算 */
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 < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
return s;
}
/* ICMP头部的作成 */
void setup_icmphdr(u_int8_t type, u_int8_t code, u_int16_t id, u_int16_t seq, struct icmphdr *icmphdr)
{
memset(icmphdr, 0, sizeof(struct icmphdr));
icmphdr->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 buf[1500];
struct sockaddr_in addr;
struct in_addr insaddr;
struct icmphdr icmphdr;
struct iphdr *recv_iphdr;
struct icmphdr *recv_icmphdr;
if (argc < 2) {
printf("Usage : %s IP_ADDRESS\n", argv[0]);
return 1;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(argv[1]);
soc = make_raw_socket(IPPROTO_ICMP);
setup_icmphdr(ICMP_ECHO, 0, 0, 0, &icmphdr);
/* ICMP包的送信 */
n = sendto(soc, (char *)&icmphdr, sizeof(icmphdr), 0, (struct sockaddr *)&addr, sizeof(addr));
if (n < 1) {
perror("sendto");
return 1;
}
/* ICMP包的受信 */
n = recv(soc, buf, sizeof(buf), 0);
if (n < 1) {
perror("recv");
return 1;
}
recv_iphdr = (struct iphdr *)buf;
/* 从IP包头获取IP包的长度,从而确定icmp包头的开始位置 */
recv_icmphdr = (struct icmphdr *)(buf + (recv_iphdr->ihl << 2));
insaddr.s_addr = recv_iphdr->saddr;
/* 检查送信包的源地址匹配受信包的目的地址 */
if (!strcmp(argv[1], inet_ntoa(insaddr)) && recv_icmphdr->type == ICMP_ECHOREPLY)
printf("icmp echo reply from %s\n", argv[1]);
close(soc);
return 0;
}
下例是binding一个原始套接字并使用: #include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<features.h>
#include<linux/if_packet.h>
#include<linux/if_ether.h>
#include<errno.h>
#include<sys/ioctl.h>
#include<net/if.h>
#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;
}
/* argv[1] is the device e.g. eth0
argv[2] is the number of packets to send */
main(int argc, char **argv)
{
int raw;
unsigned char packet[PACKET_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(argv[1], raw, ETH_P_ALL);
num_of_pkts = atoi(argv[2]);
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;
}
参见参考文献
外部链接
|
Index:
pl ar de en es fr it arz nl ja pt ceb sv uk vi war zh ru af ast az bg zh-min-nan bn be ca cs cy da et el eo eu fa gl ko hi hr id he ka la lv lt hu mk ms min no nn ce uz kk ro simple sk sl sr sh fi ta tt th tg azb tr ur zh-yue hy my ace als am an hyw ban bjn map-bms ba be-tarask bcl bpy bar bs br cv nv eml hif fo fy ga gd gu hak ha hsb io ig ilo ia ie os is jv kn ht ku ckb ky mrj lb lij li lmo mai mg ml zh-classical mr xmf mzn cdo mn nap new ne frr oc mhr or as pa pnb ps pms nds crh qu sa sah sco sq scn si sd szl su sw tl shn te bug vec vo wa wuu yi yo diq bat-smg zu lad kbd ang smn ab roa-rup frp arc gn av ay bh bi bo bxr cbk-zam co za dag ary se pdc dv dsb myv ext fur gv gag inh ki glk gan guw xal haw rw kbp pam csb kw km kv koi kg gom ks gcr lo lbe ltg lez nia ln jbo lg mt mi tw mwl mdf mnw nqo fj nah na nds-nl nrm nov om pi pag pap pfl pcd krc kaa ksh rm rue sm sat sc trv stq nso sn cu so srn kab roa-tara tet tpi to chr tum tk tyv udm ug vep fiu-vro vls wo xh zea ty ak bm ch ny ee ff got iu ik kl mad cr pih ami pwn pnt dz rmy rn sg st tn ss ti din chy ts kcg ve
Portal di Ensiklopedia Dunia