我最近发现了原始套接字,我目前正在尝试捕获使用主机命令发送的 DNS 数据包(使用 libcap 库),并在 DNS 服务器之前以错误的地址回复它。不幸的是,它似乎不起作用......我可以使用 tcpdump 看到我的数据包,但它没有传递给主机命令。这是我用于测试的代码:
#include <arpa/inet.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
typedef unsigned int u_int;
typedef unsigned short u_short;
typedef unsigned char u_char;
#include <pcap/pcap.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct dnshdr {
uint16_t id;
uint16_t flags;
uint16_t nquestion;
uint16_t nanswer;
uint16_t nauthority;
uint16_t nadditional;
};
struct msg {
struct ethhdr eth;
struct iphdr ip;
struct udphdr udp;
struct dnshdr dns;
unsigned char * data;
size_t dlen;
};
static void msg_init(uint8_t *, struct pcap_pkthdr const *, uint8_t const *);
static void msg_to_pkt(struct msg *, unsigned char *);
static uint16_t msg_len(struct msg *);
static struct msg * msg_cap(void);
static void
msg_init(uint8_t * msg, struct pcap_pkthdr const * h, uint8_t const * bytes)
{
struct msg * self;
size_t offset;
self = (struct msg *)msg;
offset = 0;
memcpy(&self->eth, bytes + offset, sizeof self->eth);
offset += sizeof self->eth;
memcpy(&self->ip, bytes + offset, sizeof self->ip);
offset += self->ip.ihl * 4;
memcpy(&self->udp, bytes + offset, sizeof self->udp);
offset += sizeof self->udp;
memcpy(&self->dns, bytes + offset, sizeof self->dns);
offset += sizeof self->dns;
self->dlen = h->len - offset;
self->data = malloc(self->dlen);
if (self->data == NULL) {
perror("malloc");
free(self);
exit(EXIT_FAILURE);
}
memcpy(self->data, bytes + offset, self->dlen);
}
static void
msg_to_pkt(struct msg * self, unsigned char * pkt)
{
memcpy(pkt, &self->eth, sizeof self->eth);
pkt += sizeof self->eth;
memcpy(pkt, &self->ip, sizeof self->ip);
pkt += sizeof self->ip;
memcpy(pkt, &self->udp, sizeof self->udp);
pkt += sizeof self->udp;
memcpy(pkt, &self->dns, sizeof self->dns);
pkt += sizeof self->dns;
memcpy(pkt, self->data, self->dlen);
}
static uint16_t
msg_len(struct msg * self)
{
uint16_t len;
len = 0;
len += sizeof self->eth;
len += sizeof self->ip;
len += sizeof self->udp;
len += sizeof self->dns;
len += self->dlen;
return len;
}
static struct msg *
msg_cap(void)
{
struct bpf_program filter;
pcap_t * p;
void * msg;
char errbuf[PCAP_ERRBUF_SIZE];
p = pcap_create("eth0", errbuf);
if (p == NULL) {
pcap_perror(p, "pcap_create");
return NULL;
}
if (pcap_activate(p) < 0) {
pcap_perror(p, "pcap_activate");
return NULL;
}
if (pcap_compile(p, &filter, "dst port 53 and udp", 1,
PCAP_NETMASK_UNKNOWN) < 0) {
pcap_perror(p, "pcap_compile");
return NULL;
}
if (pcap_setfilter(p, &filter) < 0) {
pcap_perror(p, "pcap_setfilter");
return NULL;
}
msg = malloc(sizeof (struct msg));
if (msg == NULL) {
perror("malloc");
return NULL;
}
if (pcap_loop(p, 1, &msg_init, msg) < 0) {
pcap_perror(p, "pcap_loop");
free(msg);
return NULL;
}
return msg;
}
uint16_t
cksum(void const * buf, size_t nbytes)
{
uint32_t cs = 0;
uint16_t const * p;
p = buf;
while (nbytes > 1) {
cs += *p++;
nbytes -= 2;
}
if (nbytes == 1) {
cs += *(uint8_t *)p;
}
while ((cs >> 16) != 0) {
cs = (cs & 0xFFFF) + (cs >> 16);
}
return ~(uint16_t)cs;
}
int
main(void)
{
struct msg * msg;
struct sockaddr_ll sll;
char resp[] = "\xc0\x0c\0\1\0\1\0\0\x02\x65\0\4\x7f\0\0\1";
char ethaddr[ETH_ALEN];
unsigned char * tmp;
size_t const rlen = sizeof resp - 1;
size_t mlen;
uint32_t ipaddr;
uint16_t port;
int s;
s = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);
if (s < 0) {
perror("socket");
return EXIT_FAILURE;
}
msg = msg_cap();
if (msg == NULL) {
return EXIT_FAILURE;
}
/* add DNS response */
tmp = malloc(msg->dlen + rlen);
if (tmp == NULL) {
perror("malloc");
return EXIT_FAILURE;
}
memcpy(tmp, msg->data, msg->dlen);
memcpy(tmp + msg->dlen, resp, rlen);
free(msg->data);
msg->data = tmp;
msg->dlen += rlen;
mlen = msg_len(msg);
/* reverse Ethernet address */
memcpy(ethaddr, msg->eth.h_dest, ETH_ALEN);
memcpy(msg->eth.h_dest, msg->eth.h_source, ETH_ALEN);
memcpy(msg->eth.h_source, ethaddr, ETH_ALEN);
/* reverse IP address and change some fields */
ipaddr = msg->ip.daddr;
msg->ip.daddr = msg->ip.saddr;
msg->ip.saddr = ipaddr;
msg->ip.tos = 0;
msg->ip.ttl = 53;
msg->ip.id = htons(9999);
msg->ip.tot_len = htons(mlen - sizeof msg->eth);
msg->ip.check = 0;
msg->ip.check = cksum(&msg->ip, sizeof msg->ip);
/* reverse UDP ports and change some fields */
port = msg->udp.dest;
msg->udp.dest = msg->udp.source;
msg->udp.source = port;
msg->udp.len = htons(mlen - sizeof msg->eth - sizeof msg->ip);
msg->udp.check = 0;
/* change DNS flags and nanswer fields */
msg->dns.flags = htons(0x8180);
msg->dns.nanswer = htons(1);
/* alloc buffer and send the packet */
tmp = malloc(mlen);
if (tmp == NULL) {
perror("malloc");
return EXIT_FAILURE;
}
msg_to_pkt(msg, tmp);
sll.sll_family = AF_PACKET;
sll.sll_protocol = htons(ETH_P_IP);
sll.sll_ifindex = if_nametoindex("eth0");
sll.sll_hatype = 1;
sll.sll_pkttype = PACKET_HOST;
sll.sll_halen = ETH_ALEN;
memcpy(&sll.sll_addr, msg->eth.h_dest, ETH_ALEN);
if (sendto(s, tmp, mlen, 0, (struct sockaddr *)&sll, sizeof sll) < 0) {
perror("sendto");
return EXIT_FAILURE;
}
close(s);
return 0;
}
有什么问题吗?