C 网络:Sendto() 返回 Errno 22,EINVAL
C Networking: Sendto() returning Errno 22, EINVAL
我正在尝试使用第 2、3 和 4 层组件(即以太网、IP 和 UDP)从头开始生成数据包。我的套接字被配置为使用 SOCK_RAW 作为类型和 IPPROTO_RAW 作为协议,这样我的程序可以在以后用于发送不同的协议。我严格遵守 sendto(2) 手册页 (https://linux.die.net/man/2/sendto),但是,我似乎仍然无法通过本地主机传输数据包。我的程序返回的错误是 22,即 EINVAL,表明我传递了一个不正确的参数。
我已经使用 Sockets sendto() returning EINVAL and Socket programming: sendto always fails with errno 22 (EINVAL) 来尝试解决我的问题。我什至将套接字切换为使用 SOCK_DGRAM 作为类型并使用 IPPROTO_UDP 作为协议以查看它是否与套接字有关(尽管我不相信这会提示错误论据回应)。
我的代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/ip.h>
#include <netinet/ether.h>
#include <netinet/udp.h>
#include <sys/socket.h>
#include <errno.h>
#define BUFFER 1024
int main(int argc, char *argv[]) {
/* Socket Creation */
int sockfd;
if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) {
perror("Socket");
exit(EXIT_FAILURE);
}
// This will hold all of the packet's contents
char sendbuf[BUFFER];
/* Address Stuff */
// Specify Address
in_addr_t address = inet_addr("127.0.0.1");
// Specifying Address for Sendto()
struct sockaddr_in sendto_addr;
memset(&sendto_addr, 0, sizeof(sendto_addr));
sendto_addr.sin_family = AF_INET;
sendto_addr.sin_port = htons(9623); // Make sure the port isn't contested
sendto_addr.sin_addr.s_addr = address;
// Size of whole packet
size_t total_len = 0;
/* LAYER 2 */
// Ethernet Header Configuration
struct ether_header *ether = (struct ether_header *)sendbuf;
int i;
for (i = 0; i < 6; ++i) {
ether -> ether_dhost[i] = 0x00; // Temporary data fill
ether -> ether_shost[i] = 0x00; // Temporary data fill
}
ether -> ether_type = ETHERTYPE_IP;
total_len += sizeof(struct ether_header);
/* LAYER 3 */
// IP Header Configuration
struct ip *ip = (struct ip *)(sendbuf + sizeof(struct ether_header));
ip -> ip_hl = 5;
ip -> ip_v = 4;
ip -> ip_tos = 0;
ip -> ip_p = 17;
ip -> ip_ttl = 255;
ip -> ip_src.s_addr = address;
ip -> ip_dst.s_addr = address;
total_len += sizeof(struct ip);
/* LAYER 4 */
// UDP Header Configuration
struct udphdr *udp = (struct udphdr *)(sendbuf + sizeof(struct ether_header) + \
sizeof(struct ip));
udp -> source = 123; // Gibberish to fill in later
udp -> dest = 321; // Gibberish to fill in later
udp -> check = 0;
total_len += sizeof(struct udphdr);
/* Giberrish Packet Data */
sendbuf[total_len++] = 0x00;
sendbuf[total_len++] = 0x00;
sendbuf[total_len++] = 0x00;
sendbuf[total_len++] = 0x00;
/* Fill in Rest of Headers */
udp -> len = htons(total_len - sizeof(struct ether_header) - sizeof(struct ip));
ip -> ip_len = htons(total_len - sizeof(struct ether_header));
/* Send Packet */ // ERROR OCCURS HERE
printf("Sockfd is %d\n", sockfd);
printf("Total length is %d\n", total_len);
if (sendto(sockfd, sendbuf, total_len, 0, (const struct sockaddr*)&sendto_addr, \
sizeof(sendto_addr)) < 0) {
printf("Error sending packet: Error %d.\n", errno);
perror("sendto Error");
exit(EXIT_FAILURE);
}
close(sockfd);
}
精确的控制台消息指出:
Sockfd is 3
Total length is 46
Error sending packet: Error 22.
sendto Error: Invalid argument
尤里卡!实际上是这一行:
if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) {
perror("Socket");
exit(EXIT_FAILURE);
}
应该是
if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror("Socket");
exit(EXIT_FAILURE);
}
为什么这解决了问题?好问题,很想看到有人对此主题的回应:P
我正在尝试使用第 2、3 和 4 层组件(即以太网、IP 和 UDP)从头开始生成数据包。我的套接字被配置为使用 SOCK_RAW 作为类型和 IPPROTO_RAW 作为协议,这样我的程序可以在以后用于发送不同的协议。我严格遵守 sendto(2) 手册页 (https://linux.die.net/man/2/sendto),但是,我似乎仍然无法通过本地主机传输数据包。我的程序返回的错误是 22,即 EINVAL,表明我传递了一个不正确的参数。
我已经使用 Sockets sendto() returning EINVAL and Socket programming: sendto always fails with errno 22 (EINVAL) 来尝试解决我的问题。我什至将套接字切换为使用 SOCK_DGRAM 作为类型并使用 IPPROTO_UDP 作为协议以查看它是否与套接字有关(尽管我不相信这会提示错误论据回应)。
我的代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/ip.h>
#include <netinet/ether.h>
#include <netinet/udp.h>
#include <sys/socket.h>
#include <errno.h>
#define BUFFER 1024
int main(int argc, char *argv[]) {
/* Socket Creation */
int sockfd;
if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) {
perror("Socket");
exit(EXIT_FAILURE);
}
// This will hold all of the packet's contents
char sendbuf[BUFFER];
/* Address Stuff */
// Specify Address
in_addr_t address = inet_addr("127.0.0.1");
// Specifying Address for Sendto()
struct sockaddr_in sendto_addr;
memset(&sendto_addr, 0, sizeof(sendto_addr));
sendto_addr.sin_family = AF_INET;
sendto_addr.sin_port = htons(9623); // Make sure the port isn't contested
sendto_addr.sin_addr.s_addr = address;
// Size of whole packet
size_t total_len = 0;
/* LAYER 2 */
// Ethernet Header Configuration
struct ether_header *ether = (struct ether_header *)sendbuf;
int i;
for (i = 0; i < 6; ++i) {
ether -> ether_dhost[i] = 0x00; // Temporary data fill
ether -> ether_shost[i] = 0x00; // Temporary data fill
}
ether -> ether_type = ETHERTYPE_IP;
total_len += sizeof(struct ether_header);
/* LAYER 3 */
// IP Header Configuration
struct ip *ip = (struct ip *)(sendbuf + sizeof(struct ether_header));
ip -> ip_hl = 5;
ip -> ip_v = 4;
ip -> ip_tos = 0;
ip -> ip_p = 17;
ip -> ip_ttl = 255;
ip -> ip_src.s_addr = address;
ip -> ip_dst.s_addr = address;
total_len += sizeof(struct ip);
/* LAYER 4 */
// UDP Header Configuration
struct udphdr *udp = (struct udphdr *)(sendbuf + sizeof(struct ether_header) + \
sizeof(struct ip));
udp -> source = 123; // Gibberish to fill in later
udp -> dest = 321; // Gibberish to fill in later
udp -> check = 0;
total_len += sizeof(struct udphdr);
/* Giberrish Packet Data */
sendbuf[total_len++] = 0x00;
sendbuf[total_len++] = 0x00;
sendbuf[total_len++] = 0x00;
sendbuf[total_len++] = 0x00;
/* Fill in Rest of Headers */
udp -> len = htons(total_len - sizeof(struct ether_header) - sizeof(struct ip));
ip -> ip_len = htons(total_len - sizeof(struct ether_header));
/* Send Packet */ // ERROR OCCURS HERE
printf("Sockfd is %d\n", sockfd);
printf("Total length is %d\n", total_len);
if (sendto(sockfd, sendbuf, total_len, 0, (const struct sockaddr*)&sendto_addr, \
sizeof(sendto_addr)) < 0) {
printf("Error sending packet: Error %d.\n", errno);
perror("sendto Error");
exit(EXIT_FAILURE);
}
close(sockfd);
}
精确的控制台消息指出:
Sockfd is 3
Total length is 46
Error sending packet: Error 22.
sendto Error: Invalid argument
尤里卡!实际上是这一行:
if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) {
perror("Socket");
exit(EXIT_FAILURE);
}
应该是
if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror("Socket");
exit(EXIT_FAILURE);
}
为什么这解决了问题?好问题,很想看到有人对此主题的回应:P