#define _GNU_SOURCE
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
#include <netinet/udp.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>
#include <signal.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <stdlib.h>
#include <arpa/nameser.h>
#include <assert.h>
#include "/root/projects/dnsfind/domain2name.c"
int hex2int (char hex) {
if (hex >= '0' && hex <= '9')
return hex-'0';
if (hex >= 'a' && hex <= 'f')
return 10+hex-'a';
if (hex >= 'A' && hex <= 'A')
return 10+hex-'A';
return -1;
}
int mac_pton (const char * src, unsigned char * dst) {
for (int i = 0; i < 6; i++) {
if (hex2int(src[0]) == -1 || hex2int(src[1]) == -1)
return 0;
dst[i] = hex2int(src[0]) << 4 | hex2int(src[1]);
src += 3;
}
return 1;
}
unsigned long checksum (void * data, int len) { // i cant into checksums im retarded
unsigned sum = 0;
for (int i = 0; i+1 < len; i += 2)
sum += *((unsigned char *) data + i)*256+*((unsigned char *) data + i + 1);
if (len % 2)
sum += ((unsigned char *) data)[len-1];
return sum;
}
uint16_t checksum_final (unsigned long sum) {
sum += sum >> 16;
sum &= 0xffff;
sum ^= 0xffff;
if (sum == 0)
sum = 0xffff;
return htons(sum);
}
int main (int argc, char ** argv) {
if (argc != 5) {
fprintf(stderr, "%s <dst ipv6> <src ipv6> <if index> <router mac> <querydomain>\n", argv[0]);
return 4;
}
int sock = socket(AF_PACKET, SOCK_DGRAM, htons(ETHERTYPE_IPV6));
if (sock == -1) {
perror("socket(AF_PACKET, SOCK_DGRAM, htons(ETHERTYPE_IPV6)");
return 1;
}
HEADER dns = {
.id = htons(0x1337),
.qr = 0, // question
.opcode = ns_o_query,
.rd = 1, // recursion
.qdcount = htons(1)
};
unsigned char question[5] = "";
*((uint16_t *) (question+1)) = htons(ns_t_any);
*((uint16_t *) (question+3)) = htons(ns_c_in);
struct udphdr udp = {
.source = htons(6969),
.dest = htons(53),
.len = htons(8+sizeof dns+sizeof question)
};
struct ip6_hdr ip6 = {
.ip6_ctlun.ip6_un1.ip6_un1_plen = udp.len,
.ip6_ctlun.ip6_un1.ip6_un1_hlim = 255,
.ip6_ctlun.ip6_un1.ip6_un1_nxt = IPPROTO_UDP
};
ip6.ip6_ctlun.ip6_un2_vfc |= 0x60;
switch (inet_pton(AF_INET6, argv[1], ip6.ip6_dst.s6_addr)) {
case -1:
perror("inet_pton(AF_INET6, argv[1])");
return 2;
break;
case 0:
fprintf(stderr, "naslov %s ni veljaven\n", argv[1]);
return 12;
break;
}
switch (inet_pton(AF_INET6, argv[2], ip6.ip6_src.s6_addr)) {
case -1:
perror("inet_pton(AF_INET6, argv[2])");
return 9;
break;
case 0:
fprintf(stderr, "naslov %s ni veljaven\n", argv[1]);
return 11;
break;
}
struct iovec msg[] = {
{
.iov_base = &ip6,
.iov_len = sizeof ip6
},
{
.iov_base = &udp,
.iov_len = sizeof udp
},
{
.iov_base = &dns,
.iov_len = sizeof dns
},
{
.iov_base = &question,
.iov_len = sizeof question
}
};
unsigned long sum = ip6.ip6_ctlun.ip6_un1.ip6_un1_nxt + checksum(&ip6.ip6_ctlun.ip6_un1.ip6_un1_plen, sizeof(uint16_t)) + checksum(&ip6.ip6_src, sizeof ip6.ip6_src) + checksum(&ip6.ip6_dst, sizeof ip6.ip6_dst);
for (size_t i = 1; i < sizeof msg/sizeof msg[0]; i++)
sum += checksum(msg[i].iov_base, msg[i].iov_len);
udp.check = checksum_final(sum);
udp.check = 0;
int ifindex = atoi(argv[3]);
struct sockaddr_ll dst = {
.sll_family = AF_PACKET,
.sll_ifindex = ifindex,
.sll_halen = 6,
.sll_protocol = htons(ETHERTYPE_IPV6)
};
if (!mac_pton(argv[4], dst.sll_addr)) {
fprintf(stderr, "naslov %s ni veljaven\n", argv[4]);
return 13;
}
struct mmsghdr mmsghdr = {
.msg_hdr = {
.msg_name = &dst,
.msg_namelen = sizeof dst,
.msg_iov = msg,
.msg_iovlen = sizeof msg / sizeof msg[0]
}
};
/* if (sendmmsg(sock, &mmsghdr, 1, 0) == -1) {
perror("sendmmsg(sock, &mmsghdr, 1, 0)");
return 3;
} */
if (sendmsg(sock, &mmsghdr.msg_hdr, 0) == -1) {
perror("sendmsg");
return 5;
}
return 0;
}