原始套接字Raw Socket基础-- WSADATA wsaData(转)

原文地址 http://blog.163.com/baorongzhen@126/blog/static/788692122010111941926896/


在进入Raw Socket多种强大的应用之前,我们先讲解怎样建立一个Raw Socket及怎样用建立的Raw Socket发送和接收IP包。

  建立Raw Socket
  在Windows平台上,为了使用Raw Socket,需先初始化WINSOCK:
// 启动 Winsock
WSAData wsaData;
if (WSAStartup(MAKEWORD(2, 1), &wsaData) != 0)
{
 cerr << "Failed to find Winsock 2.1 or better." << endl;
 return 1;
}

  MAKEWORD(2, 1)组成一个版本字段,2.1版,同样的,MAKEWORD(2, 2)意味着2.2版。MAKEWORD本身定义为:
inline word MakeWord(const byte wHigh, const byte wLow)
{
 return ((word)wHigh) << 8 | wLow;
}

  因此MAKEWORD(2, 1)实际等同于0x0201。同样地,0x0101可等同于MAKEWORD(1, 1)。
  与WSAStartup()的函数为WSACleanup(),在所有的socket都使用完后调用,如:
void sock_cleanup()
{
 #ifdef WIN32
  sockcount--;?
  if (sockcount == 0)
   WSACleanup();
 #endif
}

  接下来,定义一个Socket句柄:
SOCKET sd; // RAW Socket句柄

  创建Socket并将句柄赋值给定义的sd,可以使用WSASocket()函数来完成,其原型为:
SOCKET WSASocket(int af, int type, int protocol, LPWSAPROTOCOL_INFO
lpProtocolInfo, GROUP g, DWORD dwFlags);

  其中的参数定义为:
  af:地址家族,一般为AF_INET,指代IPv4(The Internet Protocol version 4)地址家族。
  type:套接字类型,如果创建原始套接字,应该使用SOCK_RAW;
  Protocol:协议类型,如IPPROTO_TCP、IPPROTO_UDP等;
  lpProtocolInfo :WSAPROTOCOL_INFO结构体指针;
  dwFlags:套接字属性标志。
  例如,下面的代码定义ICMP协议类型的原始套接字:
sd = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, 0, 0, 0);

  创建Socket也可以使用socket()函数:
SOCKET WSAAPI socket( int af, int type, int protocol);

  参数的定义与WSASocket()函数相同。
  为了使用socket()函数创建的Socket,还需要将这个Socket与sockaddr绑定:
SOCKADDR_IN addr_in;
addr_in.sin_family = AF_INET;
addr_in.sin_port = INADDR_ANY;
addr_in.sin_addr.S_un.S_addr = GetLocalIP();
nRetCode = bind(sd, (struct sockaddr*) &addr_in, sizeof(addr_in));
if (SOCKET_ERROR == nRetCode)
{
 printf("BIND Error!%d\n", WSAGetLastError());
}

  其中使用的struct sockaddr_in(即SOCKADDR_IN)为:
struct sockaddr_in
{
 unsigned short sin_family;
 unsigned short int sin_port;
 struct in_addr sin_addr;
 unsigned char sin_zero[8];
}

  而bind()函数第二个参数的struct sockaddr类型定义为:
struct sockaddr
{
 unisgned short as_family;
 char sa_data[14];
};

  实际上,bind()函数采用struct sockaddr是为了考虑兼容性,最终struct sockaddr和struct sockaddr_in的内存占用是等同的。struct sockaddr_in中的struct in_addr成员占用4个字节,为32位的IP地址,定义为:
typedef struct in_addr
{
 union
 {
  struct
  {
   u_char s_b1, s_b2, s_b3, s_b4;
  } S_un_b;
  struct
  {
   u_short s_w1, s_w2;
  } S_un_w;
  u_long S_addr;
 }
 S_un;
} IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR;

  把32位的IP地址定义为上述联合体将使用户可以以字节、半字或字方式读写同一个IP地址。同志们,注意了,这个技巧在许多软件开发中定义数据结构时被广泛采用。
  为了控制包的发送方式,我们可能会用到如下的这个十分重要的函数来设置套接字选项:
int setsockopt(
 SOCKET s, //套接字句柄
 int level, //选项level,如SOL_SOCKET
 int optname, //选项名,如SO_BROADCAST
 const char* optval, //选项值buffer指针
 int optlen //选项buffer长度
);

  例如,当level为SOL_SOCKET时,我们可以设置布尔型选项SO_BROADCAST从而控制套接字是否传送和接收广播消息。
  下面的代码通过设置IPPROTO_IP level的IP_HDRINCL选项为TRUE从而使能程序员亲自处理IP包报头:
//设置 IP 头操作选项
BOOL flag = TRUE;
setsockopt(sd, IPPROTO_IP, IP_HDRINCL, (char*) &flag, sizeof(flag);

  下面的函数用于控制套接字:
int ioctlsocket(
 SOCKET s,
 long cmd, //命令
 u_long* argp //命令参数指针
);

  如下面的代码让socket接收所有报文(sniffer模式):
u_long iMode = 1;
ioctlsocket(sd, SIO_RCVALL, & iMode); //让 sockRaw 接受所有的数据
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值