目标::将127.0.0.1 pport 8090中的udp数据包发送到本地主机端口8091。
问题:据我从wireshark可以看到,下面显示的代码实际上可以正常显示我的数据包,其中包含我选择的值。无论如何,如果在终端A上我执行nc -ulp 8091 -vv
,而在终端B上我执行程序,则什么也没有发生。我认为字符串“ hhhhhhhhhh”应该在输出中可见。
问题:为什么我看不到程序发送的输出?
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <net/ethernet.h> /* the L2 protocols */
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <stdio.h>
#include <arpa/inet.h> /* htons */
#include <sys/ioctl.h>
#include <net/if.h> /* ifreq */
#include <string.h>
#include <stdlib.h>
#include <linux/seccomp.h> /* seccomp_data */
#define BUF_SIZE 2048
//http://www.microhowto.info/howto/calculate_an_internet_protocol_checksum_in_c.html#idp22656
uint16_t ip_checksum(void* vdata,size_t length) {
// Cast the data pointer to one that can be indexed.
char* data=(char*)vdata;
// Initialise the accumulator.
uint32_t acc=0xffff;
// Handle complete 16-bit blocks.
for (size_t i=0;i+1<length;i+=2) {
uint16_t word;
memcpy(&word,data+i,2);
acc+=ntohs(word);
if (acc>0xffff) {
acc-=0xffff;
}
}
// Handle any partial block at the end of the data.
if (length&1) {
uint16_t word=0;
memcpy(&word,data+length-1,1);
acc+=ntohs(word);
if (acc>0xffff) {
acc-=0xffff;
}
}
// Return the checksum in network byte order.
return htons(~acc);
}
int main(){
const char IF[] = "lo"; // modify to change interface
int sockfd, ifindex, tx_len=sizeof(struct ether_header)+sizeof(struct iphdr)+sizeof(struct udphdr);
struct ifreq ifr;
size_t if_name_len;
char packet[BUF_SIZE];
struct ether_header *eh;
struct iphdr *iph;
struct udphdr *udph;
unsigned char *data;
u_int16_t src_port, dst_port;
struct sockaddr_ll dst_addr;
struct seccomp_data sec_payload;
const char dmac[] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
const char smac[] = {0x00, 0xd0, 0x56, 0xf2, 0xb5, 0x12};
memset(packet, 0, sizeof(packet));
eh = (struct ether_header *) packet;
iph = (struct iphdr *) (packet + sizeof(struct ether_header));
udph = (struct udphdr *) (packet + sizeof(struct ether_header) + sizeof(struct iphdr));
data = (char *)packet + sizeof(struct ether_header) + sizeof(struct iphdr) + sizeof(struct udphdr);
// create raw socket to send/receive ethernet frames that can transport all protocols
if ((sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
perror("socket");
}
// get interface name length
if_name_len = strlen(IF);
if(if_name_len < IF_NAMESIZE) {
strncpy(ifr.ifr_name, IF, strlen(IF));
ifr.ifr_name[if_name_len]=0;
}
// get the interface index number
if(ioctl(sockfd, SIOCGIFINDEX, &ifr) == -1){
perror("ioctl");
}
ifindex = ifr.ifr_ifindex;
// build ethernet header
memcpy(eh->ether_dhost, dmac, ETHER_ADDR_LEN);
memcpy(eh->ether_shost, smac, ETHER_ADDR_LEN);
eh->ether_type = htons(ETH_P_IP);
// add a struct seccomp_data as data
strcpy(data, "hhhhhhhhh");
tx_len += strlen(data);
// build ip header
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + strlen(data)); //sizeof(sec_payload)); //20+8+64
iph->id = htons(54321);
iph->frag_off = 0x00;
iph->ttl = 0xFF;
iph->protocol = IPPROTO_UDP;
iph->check = 0;
iph->saddr = inet_addr("127.0.0.1");
iph->daddr = inet_addr("127.0.0.1");
iph->check = ip_checksum(iph, iph->ihl << 2);
// build udp header
udph->source = htons(8090);
udph->dest = htons(8091);
udph->len = htons(sizeof(struct udphdr) + strlen(data));//sizeof(sec_payload));
udph->check = 0;
memset(&dst_addr, 0, sizeof(struct sockaddr_ll));
dst_addr.sll_ifindex = ifr.ifr_ifindex;
dst_addr.sll_halen = ETH_ALEN;
memcpy(dst_addr.sll_addr, dmac, ETH_ALEN);
if (sendto(sockfd, packet, tx_len, 0, (struct sockaddr*)&dst_addr, sizeof(struct sockaddr_ll)) < 0)
printf("Send failed\n");
return 0;
}
答案 0 :(得分:1)
您使用了相同的源IP地址和目标IP地址。只需将源地址更改为伪地址即可。 Linux内核必须丢弃数据包,因为它认为它不是由它发出的。
我发现在我的Linux机器上,出于测试目的而禁用反向路径过滤(sudo sysctl -w 'net.ipv4.conf.all.rp_filter=0'
)解决了该问题。我能够在同一主机上发送和接收精心制作的udp数据包。
反向路径筛选功能似乎已用于缓解使用ip地址欺骗的攻击。有什么原因可以解释为什么您从未将数据包发送到net cat应用程序。