如何使用 C 中的原始套接字发送接收到的数据包?
How can I send received packet using raw sockets in C?
我写了一些代码,但没有用。我需要将传入的数据包发送到另一台主机 (2.2.2.1)。此代码接收数据包但无法发送。我做错了什么?
我正在接收数据包,而不是将数据包复制到另一个数组,然后尝试使用 sendto() 函数发送它。
#include <unistd.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#define PCKT_LEN 8192
int main(){
int s, s1;
char buffer[PCKT_LEN];
struct sockaddr saddr;
struct sockaddr_in daddr;
memset(buffer, 0, PCKT_LEN);
s = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
if(s < 0){
printf("socket() error");
return -1;
}
int one = 1;
const int *val = &one;
if(setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof(one))<0){
printf("setsock");
return -1;
}
s1 = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
if(s1 < 0){
printf("sock2 error");
return -1;
}
if(setsockopt (s1, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0){
printf("setsock");
return -1;
}
int saddr_size = sizeof(saddr);
int daddr_size = sizeof(daddr);
int header_size = sizeof(struct iphdr) + sizeof(struct tcphdr);
unsigned int count;
daddr.sin_family = AF_INET;
daddr.sin_port = htons(1234);
daddr.sin_addr.s_addr = inet_addr ("2.2.2.1");
char *datagram, *data;
datagram = (char*)calloc(4096, sizeof(char));
struct iphdr *iph;
struct tcphdr *tcph;
int counter = 0;
while(counter != 3){
counter++;
if(recvfrom(s, buffer, PCKT_LEN , 0, &saddr, &saddr_size) < 0){
printf("recvfrom() error");
return -1;
}
else{
int i = header_size;
int packet_len = ntohs(iph->tot_len);
memset(datagram, 0 ,4096);
iph = (struct iphdr*) buffer;
tcph = (struct tcphdr*) (buffer + sizeof(struct ip));
data = buffer + sizeof(struct iphdr) + sizeof(struct tcphdr);
i = 0;
for(; i < packet_len-sizeof(struct iphdr)-sizeof(struct tcphdr); i++)
printf("%c", data[i]);
printf("\n");
memcpy(datagram, iph, sizeof(struct iphdr));
memcpy(datagram+sizeof(struct iphdr), tcph , sizeof(struct tcphdr));
memcpy(datagram+sizeof(struct iphdr)+sizeof(struct tcphdr), data,packet_len-sizeof(struct iphdr)-sizeof(struct tcphdr));
iph->daddr = daddr.sin_addr.s_addr;
if (sendto (s, datagram, packet_len, 0, &daddr, &daddr_size) < 0){
printf("sendto() error");
return -1;
}
}
}
close(s);
close(s1);
free(datagram);
return 0;
}
您没有包含 stdlib.h
,因此 calloc()
被隐式声明,因此编译器假定它是 returns int
,这将导致很多问题。
此外,除非你真的想将数据初始化为 0
,否则不要使用 calloc()
,因为如果你对数据初始化有问题,那么就不会发生什么坏事,而你永远不会知道。使用 malloc()
除非你以后要 memset(pointer, 0, size);
,这也不错,在我的情况下,我总是使用 malloc()
.
您也没有包含 unistd.h
,因此您也缺少 close()
的声明。这个没有引起问题,只是因为巧合 returns int
.
你的sendto()
调用也是错误的,最后一个参数应该是socklen_t
类型,而你传递了一个int *
,所以这样修改
sendto (s, datagram, packet_len, 0, (struct sockaddr *)&daddr, daddr_size) < 0
/* ^ no & here */
为了避免在您要求编译器发出警告时出现的某些警告,您需要将这些警告声明为变量 socklen_t
socklen_t saddr_size = sizeof(saddr);
socklen_t daddr_size = sizeof(daddr);
你还需要你在上面看到的演员表 (struct sockaddr *)&daddr
.
最重要的问题是您尝试访问 iph
而不初始化它
size_t packet_len = ntohs(iph->tot_len);
这应该在 iph = (struct iphdr *)buffer;
.
之后
造成这种情况的原因,正是你的代码太乱了,很难注意到。
你可以通过使用编译器警告来避免这一切,像这样
gcc -Wall -Wextra -Werror sourcefile.c -o executable
注意:更好地组织你的代码,很难遵循,如果像我刚才那样让别人审查它,那是不好的,对你也是不太好,因为当你几个月后再看它时,你会很生气写那个乱七八糟的人。
我写了一些代码,但没有用。我需要将传入的数据包发送到另一台主机 (2.2.2.1)。此代码接收数据包但无法发送。我做错了什么? 我正在接收数据包,而不是将数据包复制到另一个数组,然后尝试使用 sendto() 函数发送它。
#include <unistd.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#define PCKT_LEN 8192
int main(){
int s, s1;
char buffer[PCKT_LEN];
struct sockaddr saddr;
struct sockaddr_in daddr;
memset(buffer, 0, PCKT_LEN);
s = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
if(s < 0){
printf("socket() error");
return -1;
}
int one = 1;
const int *val = &one;
if(setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof(one))<0){
printf("setsock");
return -1;
}
s1 = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
if(s1 < 0){
printf("sock2 error");
return -1;
}
if(setsockopt (s1, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0){
printf("setsock");
return -1;
}
int saddr_size = sizeof(saddr);
int daddr_size = sizeof(daddr);
int header_size = sizeof(struct iphdr) + sizeof(struct tcphdr);
unsigned int count;
daddr.sin_family = AF_INET;
daddr.sin_port = htons(1234);
daddr.sin_addr.s_addr = inet_addr ("2.2.2.1");
char *datagram, *data;
datagram = (char*)calloc(4096, sizeof(char));
struct iphdr *iph;
struct tcphdr *tcph;
int counter = 0;
while(counter != 3){
counter++;
if(recvfrom(s, buffer, PCKT_LEN , 0, &saddr, &saddr_size) < 0){
printf("recvfrom() error");
return -1;
}
else{
int i = header_size;
int packet_len = ntohs(iph->tot_len);
memset(datagram, 0 ,4096);
iph = (struct iphdr*) buffer;
tcph = (struct tcphdr*) (buffer + sizeof(struct ip));
data = buffer + sizeof(struct iphdr) + sizeof(struct tcphdr);
i = 0;
for(; i < packet_len-sizeof(struct iphdr)-sizeof(struct tcphdr); i++)
printf("%c", data[i]);
printf("\n");
memcpy(datagram, iph, sizeof(struct iphdr));
memcpy(datagram+sizeof(struct iphdr), tcph , sizeof(struct tcphdr));
memcpy(datagram+sizeof(struct iphdr)+sizeof(struct tcphdr), data,packet_len-sizeof(struct iphdr)-sizeof(struct tcphdr));
iph->daddr = daddr.sin_addr.s_addr;
if (sendto (s, datagram, packet_len, 0, &daddr, &daddr_size) < 0){
printf("sendto() error");
return -1;
}
}
}
close(s);
close(s1);
free(datagram);
return 0;
}
您没有包含
stdlib.h
,因此calloc()
被隐式声明,因此编译器假定它是 returnsint
,这将导致很多问题。此外,除非你真的想将数据初始化为
0
,否则不要使用calloc()
,因为如果你对数据初始化有问题,那么就不会发生什么坏事,而你永远不会知道。使用malloc()
除非你以后要memset(pointer, 0, size);
,这也不错,在我的情况下,我总是使用malloc()
.您也没有包含
unistd.h
,因此您也缺少close()
的声明。这个没有引起问题,只是因为巧合 returnsint
.你的
sendto()
调用也是错误的,最后一个参数应该是socklen_t
类型,而你传递了一个int *
,所以这样修改sendto (s, datagram, packet_len, 0, (struct sockaddr *)&daddr, daddr_size) < 0 /* ^ no & here */
为了避免在您要求编译器发出警告时出现的某些警告,您需要将这些警告声明为变量
socklen_t
socklen_t saddr_size = sizeof(saddr); socklen_t daddr_size = sizeof(daddr);
你还需要你在上面看到的演员表
(struct sockaddr *)&daddr
.最重要的问题是您尝试访问
iph
而不初始化它size_t packet_len = ntohs(iph->tot_len);
这应该在
之后iph = (struct iphdr *)buffer;
.造成这种情况的原因,正是你的代码太乱了,很难注意到。
你可以通过使用编译器警告来避免这一切,像这样
gcc -Wall -Wextra -Werror sourcefile.c -o executable
注意:更好地组织你的代码,很难遵循,如果像我刚才那样让别人审查它,那是不好的,对你也是不太好,因为当你几个月后再看它时,你会很生气写那个乱七八糟的人。