ioctlLP:if(ioctlsocket(sock,SIO_RCvalldeCopyrightbyHuang

21cnbao 的BLOG
用户名:21cnbao
文章数:239
评论数:160
访问量:524876
注册日期:
阅读量:5863
阅读量:12276
阅读量:328215
阅读量:1036326
51CTO推荐博文
2.Raw Socket基础在进入Raw Socket多种强大的应用之前,我们先讲解怎样建立一个Raw Socket及怎样用建立的Raw Socket发送和接收IP包。2.1建立Raw Socket在Windows平台上,为了使用Raw Socket,需先初始化WINSOCK:// 启动 WinsockWSAData wsaDif (WSAStartup(MAKEWORD(2, 1), &wsaData) != 0){& cerr && "Failed to find Winsock 2.1 or better." &&& 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 | wL}因此MAKEWORD(2, 1)实际等同于0x0201。同样地,0x0101可等同于MAKEWORD(1, 1)。与WSAStartup()的函数为WSACleanup(),在所有的socket都使用完后调用,如:void sock_cleanup(){#ifdef WIN32&sockcount--;
&if (sockcount == 0)&&WSACleanup();#endif}接下来,定义一个Socket句柄:SOCKET // 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_
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_& unsigned short int sin_& struct in_addr sin_& unsigned char sin_zero[8];}而bind()函数第二个参数的struct sockaddr类型定义为:struct sockaddr{& unisgned short as_& 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_& }& S_} 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 接受所有的数据2.2Raw Socket发送报文发送报文的函数为:&int sendto(& SOCKET s,& //套接字句柄& const char* buf,&& //发送缓冲区& int len,&& //要发送的字节数& int flags,& //方式标志& const struct sockaddr* to, //目标地址& int tolen& //目标地址长度);或int send(& SOCKET s,&& //已经建立连接的套接字句柄& const char* buf,& int len,& int flags);&send()函数的第1个参数只能是一个已经建立连接的套接字句柄,所以这个函数就不再需要目标地址参数输入。&函数的返回值为实际发送的字节数,如果返回SOCKET_ERROR,可以通过WSAGetLastError()获得错误原因。请看下面的示例:int bwrote = sendto(sd, (char*)send_buf, packet_size, 0, (sockaddr*) &dest,& sizeof(dest));if (bwrote == SOCKET_ERROR){& //…发送失败& if(WSAGetLastError()==…)& {& //…& }& return - 1;}else if (bwrote & packet_size){& //…发送字节 & 欲发送字节}2.3Raw Socket接收报文接收报文的函数为:int recvfrom(& SOCKET s,& //套接字句柄& char* buf,& //接收缓冲区& int len,&&& //缓冲区字节数& int flags,&& //方式标志& struct sockaddr* from,& //源地址& int* fromlen& );或int recv(& SOCKET s, //已经建立连接的套接字句柄& char* buf,& int len,& int flags);recv()函数的第1个参数只能是一个已经建立连接的套接字句柄,所以这个函数就不再需要源地址参数输入。函数的返回值为实际接收的字节数,如果返回SOCKET_ERROR,我们可以通过WSAGetLastError()函数获得错误原因。请看下面的示例:int bread = recvfrom(sd, (char*)recv_buf, packet_size + sizeof(IPHeader), 0,& (sockaddr*) &source, &fromlen);if (bread == SOCKET_ERROR){& //…读失败& if(WSAGetLastError()==WSAEMSGSIZE)& {& //…接收buffer太小& }& return& - 1;}原始套接字按如下规则接收报文:若接收的报文中协议类型和定义的原始套接字匹配,那么,接收的所有数据拷贝入套接字中;如果套接字绑定了本地地址,那么只有接收数据IP头中对应的目的地址等于本地地址,接收到的数据才拷贝到套接字中;如果套接字定义了远端地址,那么,只有接收数据IP头中对应的源地址与远端地址匹配,接收的数据才拷贝到套接字中。2.4建立报文&在利用Raw Socket发送报文时,报文的IP头、TCP头、UDP头等需要程序员亲自赋值,从而达到极大的灵活性。下面的程序利用Raw Socket发送TCP报文,并完全手工建立报头:&int sendTcp(unsigned short desPort, unsigned long desIP){& WSADATA WSAD& SOCKET& SOCKADDR_IN addr_& IPHEADER ipH& TCPHEADER tcpH& PSDHEADER psdH
& char szSendBuf[MAX_LEN] =& { 0 };& BOOL& int rect, nTimeO
& if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)& {&&& printf("WSAStartup Error!\n");&&&& }
& if ((sock = WSASocket(AF_INET, SOCK_RAW, IPPROTO_RAW, NULL, 0,&&& WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)& {&&& printf("Socket Setup Error!\n");&&&& }& flag =& if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*) &flag, sizeof(flag)) ==&&& SOCKET_ERROR)& {&&& printf("setsockopt IP_HDRINCL error!\n");&&&& }
& nTimeOver = 1000;& if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*) &nTimeOver, sizeof&&& (nTimeOver)) == SOCKET_ERROR)& {&&& printf("setsockopt SO_SNDTIMEO error!\n");&&&& }& addr_in.sin_family = AF_INET;& addr_in.sin_port = htons(desPort);& addr_in.sin_addr.S_un.S_addr = inet_addr(desIP);
& //填充IP报头& ipHeader.h_verlen = (4 && 4 | sizeof(ipHeader) / sizeof(unsigned long));& // ipHeader.tos=0;& ipHeader.total_len = htons(sizeof(ipHeader) + sizeof(tcpHeader));& ipHeader.ident = 1;& ipHeader.frag_and_flags = 0;& ipHeader.ttl = 128;& ipHeader.proto = IPPROTO_TCP;& ipHeader.checksum = 0;& ipHeader.sourceIP = inet_addr("localhost");& ipHeader.destIP = desIP;
& //填充TCP报头& tcpHeader.th_dport = htons(desPort);& tcpHeader.th_sport = htons(SOURCE_PORT); //源端口号& tcpHeader.th_seq = htonl(0x);& tcpHeader.th_ack = 0;& tcpHeader.th_lenres = (sizeof(tcpHeader) / 4 && 4 | 0);& tcpHeader.th_flag = 2;& //标志位探测,2是SYN & tcpHeader.th_win = htons(512);& tcpHeader.th_urp = 0;& tcpHeader.th_sum = 0;
& psdHeader.saddr = ipHeader.sourceIP;& psdHeader.daddr = ipHeader.destIP;& psdHeader.mbz = 0;& psdHeader.ptcl = IPPROTO_TCP;& psdHeader.tcpl = htons(sizeof(tcpHeader));
& //计算校验和& memcpy(szSendBuf, &psdHeader, sizeof(psdHeader));& memcpy(szSendBuf + sizeof(psdHeader), &tcpHeader, sizeof(tcpHeader));& tcpHeader.th_sum = checksum((unsigned short*)szSendBuf, sizeof(psdHeader) + sizeof&&& (tcpHeader));
& memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));& memcpy(szSendBuf + sizeof(ipHeader), &tcpHeader, sizeof(tcpHeader));& memset(szSendBuf + sizeof(ipHeader) + sizeof(tcpHeader), 0, 4);& ipHeader.checksum = checksum((unsigned short*)szSendBuf, sizeof(ipHeader) + sizeof&&& (tcpHeader));
& memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));
& rect = sendto(sock, szSendBuf, sizeof(ipHeader) + sizeof(tcpHeader), 0,&&& (struct sockaddr*) &addr_in, sizeof(addr_in));& if (rect == SOCKET_ERROR)& {&&& printf("send error!:%d\n", WSAGetLastError());&&&& }& else&&& printf("send ok!\n");
& closesocket(sock);& WSACleanup();
&}本文出自 “” 博客,请务必保留此出处
了这篇文章
类别:┆阅读(0)┆评论(0)在线等ioctlLP:if(ioctlsocket(sock,SIO_RCVALLif(add_or_not==1)_百度知道1391人阅读
C、C++(35)
接收流经网卡的数据包,使用混杂模式。使用多线程+完成端口,数据处理部分和协议分析未完成。。。
/* Authors: perry peng
* Date: September 11, 2011
* Project Name:
* Project Version:
* Module: main.c
#include &stdio.h&
#include &malloc.h&
#include &winsock2.h&
#include &Ws2tcpip.h&
#include &Mstcpip.h&
#include &Iphlpapi.h&
#pragma comment(lib, &Ws2_32&)
#pragma comment(lib, &Iphlpapi&)
#define MAX_PACKET_LENGTH 65535
#define ERR_MSG(m)
fprintf(stderr, &%s [%d] &, __FILE__, __LINE__ - 2); \
if (!print_err_msg(GetLastError(), NULL))
fprintf(stderr, m);
#define WSA_ERR_MSG(m)
fprintf(stderr, &%s [%d] &, __FILE__, __LINE__ - 2); \
if (!print_err_msg(WSAGetLastError(), NULL)) \
fprintf(stderr, m);
#define FATAL_ERROR(m)
ERR_MSG(m);
#define WSA_FATAL_ERROR(m)
WSA_ERR_MSG(m);
#define PRINT_IP(h, t)
fprintf(stdout, (h));
if (!print_addr_info((PIP_ADDR_LIST)adp_info-&First##t##Address)) \
fprintf(stdout, &No %s Addresses\n&, #t);
#define HALLOC(x)
HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (x))
#define REALLOC(p, x)
HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (p), (x))
#define HFREE(p)
HeapFree(GetProcessHeap(), 0, (p))
#define AALLOC(x)
_aligned_malloc((x), MEMORY_ALLOCATION_ALIGNMENT)
#define AFREE(x)
_aligned_free((x))
typedef PIP_ADAPTER_UNICAST_ADDRESS PIP_ADDR_LIST;
typedef union _ADDR_IN
u_short Words[20];
struct sockaddr_in ipv4;
struct sockaddr_in6 ipv6;
} ADDR_IN, *LPADDR_IN;
typedef struct _tagPacketNode
SLIST_ENTRY
WSAOVERLAPPED
struct _tagPacketNode *
} PACKET, *LPPACKET;
// WARNING !!!
All list items must be aligned on a MEMORY_ALLOCATION_ALIGNMENT
// WARNING !!!
otherwise, this function will behave unpredictably.
PSLIST_HEADER
packet_list = NULL;
packet_free_list = NULL;
CRITICAL_SECTION
volatile int
packet_index = 0,
packet_count = 0;
int print_addr_info(PIP_ADDR_LIST);
int print_err_msg(long, char *);
BOOL WINAPI ctrl_callback(DWORD);
DWORD WINAPI work_thread(LPVOID);
void begin_recv_packet(SOCKET);
int get_key_input(LPDWORD, DWORD, int);
int get_socket_addr(LPADDR_IN, short, unsigned short);
sck_ioctl,
*threads = NULL,
iocp = NULL;
socket_raw = INVALID_SOCKET;
SYSTEM_INFO
if (!SetConsoleCtrlHandler(ctrl_callback, TRUE))
FATAL_ERROR(&SetConsoleCtrlHandler() failed to install console handler.\n&);
// 初始化线程打印同步对象。
InitializeCriticalSection(&crit_sec);
// 初始化SOCKET。
if (WSAStartup(MAKEWORD(2, 2), &wsa_init) ||
LOBYTE(wsa_init.wVersion) != 2 ||
HIBYTE(wsa_init.wVersion) != 2)
WSA_FATAL_ERROR(&Failed to initialize socket.\n&);
// 显示当前主机的网络适配器列表,供用户选择。
if (!get_socket_addr(&addr, AF_UNSPEC, 0))
// 创建新SOCKET。
socket_raw = WSASocket(addr.family, SOCK_RAW, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);
if (socket_raw == INVALID_SOCKET)
WSA_FATAL_ERROR(&Failed to create socket.\n&);
// 绑定到本地某个网卡。
if (bind(socket_raw, (struct sockaddr *)&addr, sizeof(ADDR_IN)) == SOCKET_ERROR)
WSA_FATAL_ERROR(&Failed to call bind.\n&);
// 设置SOCKET I/O CODE,打开RCVALL,开启网卡混杂模式将接收所有到达此网卡上的数据包。
sck_ioctl = RCVALL_ON;
if (WSAIoctl(socket_raw, SIO_RCVALL, &sck_ioctl, sizeof(sck_ioctl), NULL, 0, &i, NULL, NULL) == SOCKET_ERROR)
WSA_FATAL_ERROR(&Failed to call WSAIoctl.\n&);
// 创建新的完成端口并绑定SOCKET句柄到完成端口。
iocp = CreateIoCompletionPort((HANDLE)socket_raw, NULL, socket_raw, 0);
if (iocp == NULL)
FATAL_ERROR(&Failed to call CreateIoCompletionPort.\n&);
// 获得当前系统识别到的处理器数量。
GetSystemInfo(&sys_info);
threads_num = sys_info.dwNumberOfProcessors * 2;
// 为链表头申请内存。
packet_list = (PSLIST_HEADER)AALLOC(sizeof(SLIST_HEADER));
if (packet_list == NULL)
FATAL_ERROR(&Failed to allocated memory.&);
// 初始化链表。
InitializeSListHead(packet_list);
// 申请线程组所需的内存。
threads = (HANDLE*)HALLOC(threads_num * sizeof(HANDLE));
if (!threads)
FATAL_ERROR(&Failed to allocate memory for thread array.\n&);
bLoop = 1;
// 创建线程组。
for (i = 0; i & threads_ i++)
threads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)work_thread, (LPVOID)iocp, 0, NULL);
if (threads[i] == NULL)
ERR_MSG(&Failed to create thread array.&);
for (; i & threads_ i++)
threads[i] = NULL;
goto InitThreadsF
// 等待用户输入退出键关闭程序。
while (get_key_input(&i, 0, TRUE))
switch (i)
case VK_RETURN:
// 开始扑获网络包。
packet_index = 0;
begin_recv_packet(socket_raw);
InitThreadsFailed:
bLoop = 0;
WaitForMultipleObjects(threads_num, threads, TRUE, INFINITE);
Exception:
if (threads)
for (i = 0; i & threads_ i++)
CloseHandle(threads[i]);
// 释放掉线程数组内存。
HFREE(threads);
threads = NULL;
if (socket_raw != INVALID_SOCKET)
closesocket(socket_raw);
if (iocp != NULL)
CloseHandle(iocp);
if (packet_list)
// 清除掉链表所有节点。
InterlockedFlushSList(packet_list);
// 释放掉链表头占用的内存。
AFREE(packet_list);
packet_list = NULL;
while (packet_free_list != NULL)
packet = packet_free_
if (packet-&wsa.buf)
HFREE(packet-&wsa.buf);
// 指向前一个链表节点。
packet_free_list = packet-&
// 释放掉链单元占用的内存。
AFREE(packet);
// 删除线程打印同步对象。
DeleteCriticalSection(&crit_sec);
WSACleanup();
// 取消CtrlHandler处理列程。
SetConsoleCtrlHandler(ctrl_callback, FALSE);
begin_recv_packet(socket_raw)
SOCKET socket_
// 先从队列中查看是否有空闲的内存单元。
packet = (LPPACKET)InterlockedPopEntrySList(packet_list);
if (packet == NULL)
// 如果在队列中没有找到,将重新新建一个内存单元供WSARecv使用。
packet = (LPPACKET)AALLOC(sizeof(PACKET));
if (packet == NULL)
ERR_MSG(&Memory allocation failed.\n&);
ZeroMemory(packet, sizeof(PACKET));
// 新的内存单元的数据缓冲区内存申请。
packet-&wsa.len = MAX_PACKET_LENGTH;
packet-&wsa.buf = HALLOC(MAX_PACKET_LENGTH);
if (packet-&wsa.buf == NULL)
ERR_MSG(&Memory allocation failed.\n&);
AFREE(packet);
InterlockedIncrement(&packet_count);
// 保护对链表的访问。
EnterCriticalSection(&crit_sec);
// 任何新建立的数据缓冲区将存入另外一个列表中,确保释放时不会遗漏。
packet-&forward = packet_free_
packet_free_list =
LeaveCriticalSection(&crit_sec);
// 接收包计数。
InterlockedIncrement(&packet_index);
// 填充信息。
packet-&index = packet_
// 全局的包索引。
packet-&socket = socket_
// 使用此包的SOCKET句柄。
packet-&flags = 0;
// 开始异步接收数据包。
if (WSARecv(socket_raw, &packet-&wsa, 1, &packet-&length, &packet-&flags, &packet-&overlap, NULL) == SOCKET_ERROR)
if ((error = WSAGetLastError()) != WSA_IO_PENDING)
WSASetLastError(error);
WSA_ERR_MSG(&WSARecv was failed.\n&);
BOOL WINAPI
ctrl_callback(event)
INPUT_RECORD
switch (event)
case CTRL_C_EVENT:
case CTRL_CLOSE_EVENT:
case CTRL_BREAK_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
fprintf(stdout, &System is exiting...\n&);
ZeroMemory(&record, sizeof(INPUT_RECORD));
record.EventType = KEY_EVENT;
record.Event.KeyEvent.bKeyDown = 1;
record.Event.KeyEvent.wRepeatCount = 1;
record.Event.KeyEvent.wVirtualKeyCode = VK_ESCAPE;
// 模拟用户按下ESC按键。
WriteConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &record, 1, &length);
Sleep(10);
// 指示所有工作线程停止工作。
if (bLoop)
bLoop = 0;
// unknown type--better pass it on.
return FALSE;
return TRUE;
DWORD WINAPI
work_thread(data)
iocp = (HANDLE)
LPWSAOVERLAPPED
display[128];
while (bLoop)
overlap = NULL;
// 从完成端口队列中取得一个已经完成的I/O操作。
if (!GetQueuedCompletionStatus(iocp, &transferred, &key, &overlap, 500))
//INFINITE, in milliseconds
error = GetLastError();
if (error == WAIT_TIMEOUT)
// 没有数据,是其它原因退出线程。
if (overlap == NULL)
// 取得链表单元指针。
packet = (LPPACKET)(((LPBYTE)overlap) - sizeof(SLIST_ENTRY));
// 完成一个接收后在处理数据前就可以立即接收下一个包。
begin_recv_packet(packet-&socket);
// 接到来自WSARev的数据,开始处理包信息。
sprintf(display, &RX[%04X], I: %04d L: %04d, &, GetCurrentThreadId(), packet-&index, packet-&length);
for (i = 0; i & 16; i++)
sprintf(&display[strlen(display)], &%02X &, (BYTE)packet-&wsa.buf[i]);
sprintf(&display[strlen(display)], &\n&);
fprintf(stdout, display);
// 清除相关数据。
ZeroMemory(&packet-&overlap, sizeof(WSAOVERLAPPED));
// 数据包使用完后再重先入队,以便让其它线程使用。
InterlockedPushEntrySList(packet_list, (PSLIST_ENTRY)packet);
fprintf(stdout, &Thread %04X was exited.\n&, GetCurrentThreadId());
print_err_msg(errorId, format)
long errorId;
text = NULL;
// Gets the message string by an error code.
length = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorId, 0,
(LPSTR)&text,
if (length == 0)
fprintf(stderr, &FormatMessage was failed, error:0x%08x, format:0x%08x\n&, GetLastError(), errorId);
fprintf(stderr, &%08X:&, errorId);
if (format != NULL)
fprintf(stderr, format, text);
fprintf(stderr, text);
// Free the buffer allocate by the FormatMessage function.
LocalFree(text);
get_key_input(key, exitkey, keydown)
INPUT_RECORD
*key = -1;
// 读取一组控制台事件记录。
if (!ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &record, 1, &length) ||
ERR_MSG(&Failed to get user key events.&);
Sleep(100);
// 读取键盘输入失败,返回TRUE进入下一个读取动作。
// 判断是否为键盘事件。
if (record.EventType != KEY_EVENT ||
!(keydown ? record.Event.KeyEvent.bKeyDown: !record.Event.KeyEvent.bKeyDown))
// 返回当前KEY值。
*key = record.Event.KeyEvent.wVirtualKeyC
// 如果是指定的退出按键或ESC则返回FALSE。
return !(*key == exitkey || *key == VK_ESCAPE);
print_addr_info(addrinfo)
PIP_ADDR_LIST
IPv6版本IP地址需要更多的储存空间。
For an IPv4 address, this buffer should be large enough to hold at least 16 characters.
For an IPv6 address, this buffer should be large enough to hold at least 46 characters.
ip_addr[64];
bytes = 0;
while (addrinfo != NULL)
if (bytes & 0)
fprintf(stdout, &\n
// 将IP地址信息转换为字符串。
bytes = sizeof(ip_addr);
if (WSAAddressToString(addrinfo-&Address.lpSockaddr, addrinfo-&Address.iSockaddrLength, NULL, ip_addr, &bytes) == ERROR_SUCCESS)
fprintf(stdout, ip_addr);
switch (WSAGetLastError())
case ERROR_SUCCESS:
fprintf(stdout, ip_addr);
case WSAEFAULT:
fprintf(stdout, &Invalid buffer space.&);
case WSAEINVAL:
fprintf(stdout, &Incorrect parameter.&);
case WSANOTINITIALISED:
fprintf(stdout, &Winsock 2 DLL has not been initialized.&);
return FALSE;
case WSAENOBUFS:
fprintf(stdout, &No buffer space is available.&);
addrinfo = addrinfo-&N
if (bytes == 0)
fprintf(stdout, &\n&);
get_socket_addr(addr, family, port)
PIP_ADAPTER_ADDRESSES
adp_info_list = NULL,
CONSOLE_SCREEN_BUFFER_INFO
PIP_ADAPTER_UNICAST_ADDRESS
addr_in = NULL;
succeed = 9,
vista = (GetVersion() & 0xff) &= 6;
// 为链表分配一定的储存空间。
bytes = sizeof(IP_ADAPTER_ADDRESSES);
adp_info_list = (PIP_ADAPTER_ADDRESSES)HALLOC(bytes);
if (adp_info_list == NULL)
FATAL_ERROR(&Failed to allocate heap memory.\n&);
i = GAA_FLAG_INCLUDE_PREFIX;
if (vista)
i |= GAA_FLAG_INCLUDE_GATEWAYS | GAA_FLAG_INCLUDE_WINS_INFO;
// 获得储存有网卡信息的链表。
while ((result = GetAdaptersAddresses(AF_UNSPEC, i, NULL, adp_info_list, &bytes)) != ERROR_SUCCESS)
if (result != ERROR_BUFFER_OVERFLOW)
FATAL_ERROR(&Failed to get address information.\n&);
// 如果是内存不足,将重新申请内存,直到足够为止。
adp_info_list = (PIP_ADAPTER_ADDRESSES)REALLOC(adp_info_list, bytes);
if (adp_info_list == NULL)
FATAL_ERROR(&Failed to allocate heap memory.\n&);
// 获得控制台窗口尺寸,防止内容太长影响输出格式。
if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &con_info))
con_info.dwSize.X = 1024;
con_info.dwSize.X -= 22;
index = 0;
// 打印本机所有网卡信息。
adp_info = adp_info_
while (adp_info)
// 只需要列出Ethernet网卡。
if (adp_info-&IfType != IF_TYPE_ETHERNET_CSMACD &&
adp_info-&IfType != IF_TYPE_IEEE80211)
adp_info = adp_info-&N
adp_info-&IfIndex = ++
fprintf(stdout, &%d
&, adp_info-&IfIndex);
if (wcslen(adp_info-&Description) & con_info.dwSize.X)
for (i = 0; i & con_info.dwSize.X; i++)
fprintf(stdout, &%wC&, adp_info-&Description[i]);
fprintf(stdout, & ...\n&);
fprintf(stdout, &%wS\n&, adp_info-&Description);
fprintf(stdout, &
if (adp_info-&PhysicalAddressLength & 0)
for (i = 0; i & adp_info-&PhysicalAddressL i++)
if (i & 0)
fprintf(stdout, &-&);
fprintf(stdout, &%02X&, adp_info-&PhysicalAddress[i]);
fprintf(stdout, &\n&);
fprintf(stdout, &00-00-00-00-00-00\n&);
PRINT_IP(&
&, Anycast);
PRINT_IP(&
&, Multicast);
PRINT_IP(&
&, Unicast);
PRINT_IP(&
&, DnsServer);
//fprintf(stdout, &
DNS Suffix: %wS\n&, adp_info-&DnsSuffix);
if (vista)
PRINT_IP(&
&, Gateway);
PRINT_IP(&
&, WinsServer);
fprintf(stdout, &
if (adp_info-&OperStatus == IfOperStatusUp ||
adp_info-&OperStatus == IfOperStatusTesting)
fprintf(stdout, &TX=%I64dMBps, &, adp_info-&TransmitLinkSpeed / 1024 / 1024);
fprintf(stdout, &RX=%I64dMBps\n&, adp_info-&ReceiveLinkSpeed / 1024 / 1024);
fprintf(stdout, &TX=0MBps, RX=0MBps\n&);
fprintf(stdout, &
switch (adp_info-&OperStatus)
case IfOperStatusUp:
fprintf(stdout, &Up\n&);
case IfOperStatusDown:
fprintf(stdout, &Down\n&);
case IfOperStatusTesting:
fprintf(stdout, &Testing\n&);
case IfOperStatusUnknown:
fprintf(stdout, &Unknown\n&);
case IfOperStatusDormant:
fprintf(stdout, &Dormant\n&);
case IfOperStatusNotPresent:
fprintf(stdout, &Not Present\n&);
case IfOperStatusLowerLayerDown:
fprintf(stdout, &Lower Layer Down\n&);
fprintf(stdout, &\n&);
adp_info = adp_info-&N
fprintf(stdout, &Please select a network adapter:&);
adp_info = NULL;
// 等待用户输入一个数值表示选择某块网卡。
while (get_key_input(&i, 0, TRUE))
if (i &= 0x30 && i &= 0x39)
adp_info = adp_info_
while (adp_info != NULL)
// 判断是否为当前用户所选择的网络适配器编号。
if ((adp_info-&IfIndex + 0x30) != i)
adp_info = adp_info-&N
// 此网络适配器没有一个有效的IP地址。
if (adp_info-&FirstUnicastAddress == NULL)
// 指定IP类型由参数family定义。
// 如果family未定义就默认为是IPV4地址。
if (index == AF_UNSPEC)
index = AF_INET;
while (TRUE)
uni_addr = adp_info-&FirstUnicastA
while (uni_addr != NULL)
addr_in = (LPADDR_IN)uni_addr-&Address.lpS
if (addr_in-&family == index)
uni_addr = uni_addr-&N
// 找到一个指定的地址。
if (addr_in-&family == index)
// 如果指定了IP类型但未匹配到正确的IP。
if (family != AF_UNSPEC)
index = 0;
// 如果没有找到任何IPV4地址,再找IPV6地址。
switch (index)
case AF_INET:
// IPV4没有就找IPV6.
index = AF_INET6;
case AF_INET6:
// IPV6没有就找...。
// 决定何时退出。如果连IPV6也没有找到。
if (index == AF_INET6)
// 什么IP地址也没有找到。
index = 0;
// 未能找到IPV4或IPV6地址。
if (index == 0)
// 计算地址结构长度。
bytes = uni_addr-&Address.iSockaddrL
if (bytes == 0)
i = sizeof(ADDR_IN);
// 打印当前选择的IP地址可能是IPV4或IPV6。
if (WSAAddressToString((LPSOCKADDR)addr_in, bytes, NULL, (char*)addr, &i) == ERROR_SUCCESS)
fprintf(stdout, &\nOK, the IP address %s was selected.\n&, (char*)addr);
fprintf(stdout, &\nOK, the adapter %c was selected.\n&, i);
// 将选择的网卡的IP地址传给socket挷定。
if (bytes & sizeof(ADDR_IN))
bytes = sizeof(ADDR_IN);
memcpy(addr, addr_in, bytes);
addr-&family = addr_in-&
addr-&port =
succeed = 1;
if (!succeed)
if (adp_info == NULL)
fprintf(stdout, &\nNo adapter found which match your selection.\n&);
if (index == 0)
fprintf(stdout, &\nNo IP address found which match&);
switch (family)
case AF_INET:
fprintf(stdout, & IPV4.\n&);
case AF_INET6:
fprintf(stdout, & IPV6.\n&);
fprintf(stdout, &\nThe adapter %c doesn't have a valid IP address.\n&, i);
Exception:
if (adp_info_list != NULL)
HFREE(adp_info_list);
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:209842次
积分:3501
积分:3501
排名:第6673名
原创:139篇
转载:97篇
评论:26条
(3)(7)(1)(3)(1)(3)(2)(5)(2)(2)(3)(3)(8)(5)(10)(22)(11)(14)(20)(66)(5)(17)(7)(1)(3)(1)(2)(1)(9)

我要回帖

更多关于 vallde 的文章

 

随机推荐