Last active
August 20, 2020 21:22
-
-
Save majek/cd389095a4d38af649b203e12dcee340 to your computer and use it in GitHub Desktop.
conntrack experiment
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define PFATAL(x...) \ | |
do { \ | |
fprintf(stderr, "[-] SYSTEM ERROR : " x); \ | |
fprintf(stderr, "\n\tLocation : %s(), %s:%u\n", __FUNCTION__, __FILE__, \ | |
__LINE__); \ | |
perror(" OS message "); \ | |
fprintf(stderr, "\n"); \ | |
exit(EXIT_FAILURE); \ | |
} while (0) | |
static inline uint32_t ip_add_csum(uint8_t *p, int len) { | |
uint32_t sum =0; | |
int i; | |
for(i=0; i< len-1; i+=2) { | |
sum += p[i] | (p[i+1]<<8); | |
} | |
if (len%2) { | |
sum += p[len-1]; | |
} | |
return sum; | |
} | |
static inline uint16_t ip_cksum_carry(uint32_t x) { | |
x = (x >> 16) + (x & 0xffff); | |
x = (x + (x >> 16)) & 0xffff; | |
return ~x; | |
} | |
static inline uint16_t compute_ip_checksum(struct iphdr *iphdr) { | |
uint32_t sum = 0; | |
sum += ip_add_csum((uint8_t*)iphdr, iphdr->ihl * 4); | |
// compensate for existing checksum | |
sum -= iphdr->check; | |
return ip_cksum_carry(sum); | |
} | |
static inline uint16_t compute_tcp_checksum(struct iphdr *iphdr, struct tcphdr *tcphdr) { | |
uint16_t tcp_len = ntohs(iphdr->tot_len) - iphdr->ihl*4; | |
uint32_t sum = 0; | |
sum += ip_add_csum((uint8_t*)(&iphdr->saddr), 8); | |
sum += htons(iphdr->protocol); | |
sum += htons(tcp_len); | |
sum += ip_add_csum((uint8_t*)tcphdr, tcp_len); | |
// 16th byte is checksum (may be non-zero), compensate | |
sum -= tcphdr->check; | |
return ip_cksum_carry(sum); | |
} | |
/* utils.c */ | |
const char *optstring_from_long_options(const struct option *opt); | |
int setup_server(struct sockaddr_storage *addr); | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <errno.h> | |
#include <fcntl.h> | |
#include <limits.h> | |
#include <linux/if_tun.h> | |
#include <linux/ip.h> | |
#include <linux/tcp.h> | |
#include <net/if.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/ioctl.h> | |
#include <sys/socket.h> | |
#include <sys/stat.h> | |
#include <sys/types.h> | |
#include <sys/uio.h> | |
#include <unistd.h> | |
#include <netinet/in.h> | |
#include <getopt.h> | |
#include <arpa/inet.h> | |
#include "common.h" | |
void iface_hwaddr(int sd, const char *if_name, uint8_t *hwaddr) | |
{ | |
struct ifreq ifreq; | |
memset(&ifreq, 0, sizeof(ifreq)); | |
strncpy(ifreq.ifr_name, if_name, sizeof(ifreq.ifr_name)); | |
int r = ioctl(sd, SIOCGIFHWADDR, &ifreq); | |
if (r < 0) { | |
PFATAL("ioctl(%s, SIOCGIFHWADDR)", if_name); | |
} | |
memcpy(hwaddr, ifreq.ifr_hwaddr.sa_data, 6); | |
} | |
static void print_usage() | |
{ | |
printf( | |
#include "help.txt" | |
); | |
} | |
int main(int argc, char *argv[]) { | |
char *iface_name = "tap0"; | |
struct sockaddr_in src = { | |
.sin_family = AF_INET, | |
.sin_port = htons(1), | |
.sin_addr = {htonl(INADDR_LOOPBACK)}, | |
}; | |
struct sockaddr_in dst = { | |
.sin_family = AF_INET, | |
.sin_port = htons(80), | |
.sin_addr = {htonl(INADDR_LOOPBACK)}, | |
}; | |
{ | |
static struct option long_options[] = { | |
{"iface", required_argument, 0, 'i'}, | |
{"src", required_argument, 0, 's'}, | |
{"dst", required_argument, 0, 'd'}, | |
{"help", no_argument, 0, 'h'}, | |
{NULL, 0, 0, 0}}; | |
optind = 1; | |
while (1) { | |
int option_index = 0; | |
int arg = getopt_long( | |
argc, argv, | |
optstring_from_long_options(long_options), | |
long_options, &option_index); | |
if (arg == -1) { | |
break; | |
} | |
switch (arg) { | |
default: | |
case 0: | |
fprintf(stderr, "Unknown option: %s", | |
argv[optind]); | |
exit(-1); | |
break; | |
case '?': | |
exit(-1); | |
break; | |
case 'i': | |
iface_name = optarg; | |
break; | |
case 's': | |
inet_pton(AF_INET, optarg, &src.sin_addr); | |
break; | |
case 'd': | |
inet_pton(AF_INET, optarg, &dst.sin_addr); | |
break; | |
case 'h': | |
print_usage(); | |
exit(0); | |
break; | |
} | |
} | |
} | |
{ | |
char *last_arg = argv[optind]; | |
if (last_arg != NULL) { | |
fprintf(stderr, "[!] unrecognized parameter %s\n", last_arg); | |
exit(-1); | |
} | |
} | |
int main_fd = open("/dev/net/tun", O_RDWR); | |
if (main_fd < 0) { | |
PFATAL("open(\"/dev/net/tun\")"); | |
} | |
struct ifreq ifr = { | |
.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_MULTI_QUEUE, | |
// .ifr_name = iface_name, | |
}; | |
if (iface_name != NULL) { | |
strncpy(ifr.ifr_name, iface_name, IFNAMSIZ); | |
} | |
int r = ioctl(main_fd, TUNSETIFF, &ifr); | |
if (r < 0) { | |
PFATAL("ioctl(%s, TUNSETIFF, IFF_TAP)", | |
ifr.ifr_name); | |
} | |
if (iface_name != NULL) { | |
r = ioctl(main_fd, TUNSETPERSIST, 1); | |
if (r < 0) { | |
PFATAL("ioctl(%s, TUNSETPERSIST)", | |
ifr.ifr_name); | |
} | |
} | |
/* From the kernel commit: | |
* | |
* > For now the accounting is essentially disabled by default | |
* > for backwards compatibility. In particular, we set the | |
* > cap to INT_MAX. This is so that existing applications | |
* > don't get confused by the sudden arrival EAGAIN errors. | |
*/ | |
int sndbuf = 0; | |
r = ioctl(main_fd, TUNGETSNDBUF, &sndbuf); | |
if (r < 0) { | |
PFATAL("ioctl(%s, TUNGETSNDBUF)", ifr.ifr_name); | |
} | |
/* struct iface iface = {}; */ | |
uint8_t hwaddr[6]; | |
iface_hwaddr(main_fd, ifr.ifr_name, hwaddr); | |
/* strncpy(iface.name, ifr.ifr_name, sizeof(iface.name)); */ | |
/* iface.fd = main_fd; */ | |
/* Sort out global settings */ | |
fprintf(stderr, | |
"[ ] Opened tap interface %s sndbuf=%i " | |
"hwaddr=%02x:%02x:%02x:%02x:%02x:%02x\n", | |
ifr.ifr_name, | |
sndbuf == INT_MAX ? -1 : sndbuf, hwaddr[0], | |
hwaddr[1], hwaddr[2], hwaddr[3], | |
hwaddr[4], hwaddr[5]); | |
uint8_t packet[2048]; | |
packet[12] = 0x08; | |
packet[13] = 0x00; | |
/* "\x00\x00\x00\x00\x00\x01" // smac */ | |
/* "\x00\x00\x00\x00\x00\x01" // dmac */ | |
/* "\x08\x00" // ipv4 */ | |
/* "\x45\x00\x00\x34" */ | |
/* "\x00\x00\x40\x00" */ | |
/* "\x40\x06" */ | |
/* "\x3c\xc2" // checksum */ | |
/* "\x7f\x00\x00\x01" // sip */ | |
/* "\x7f\x00\x00\x01" // dip */ | |
/* "\x00\x01" // sport */ | |
/* "\x00\x51" // dport */ | |
/* "\xde\xad\xbe\xef" // seq */ | |
/* "\xfa\x01\xba\xbe" // ack */ | |
/* "\x50\x02" // hlen + flags */ | |
/* "\x02\x00" // window size */ | |
/* "\x90\x18\x00\x00" // checksum + urg */ | |
/* "\x01\x01\x08\x0a" */ | |
/* "\x53\xc6\xf6\x39\x53\xc6\xf6\x39" */ | |
/* }; */ | |
struct sockaddr_in srv_addr = { | |
.sin_family = AF_INET, | |
.sin_port = htons(80), | |
.sin_addr = {htonl(INADDR_ANY)}, | |
}; | |
int srv_fd = setup_server((struct sockaddr_storage*)&srv_addr); | |
int i; | |
for (i=0; i<10; i++) { | |
struct iphdr *iphdr = (struct iphdr*)&packet[14]; | |
*iphdr = (struct iphdr){ | |
.ihl = 5, | |
.version = 4, | |
.tot_len = htons(40+1), | |
.ttl = 64, | |
.protocol = IPPROTO_TCP, | |
.saddr = src.sin_addr.s_addr, | |
.daddr = dst.sin_addr.s_addr, | |
}; | |
iphdr->check = compute_ip_checksum(iphdr); | |
struct tcphdr *tcphdr = (struct tcphdr*)&packet[14+20]; | |
*tcphdr = (struct tcphdr){ | |
.source = htons(ntohs(src.sin_port)+i), | |
.dest = dst.sin_port, | |
.seq = htonl(0xdeadbeef), | |
.ack_seq = htonl(0xbadbabe), | |
.doff = 5, | |
.syn = 1, | |
.window = htons(0x0200), | |
}; | |
tcphdr->check = compute_tcp_checksum(iphdr, tcphdr); | |
int packet_len = ntohs(iphdr->tot_len) + 14; | |
char buf[2048]; | |
memcpy(buf, hwaddr, 6); | |
memcpy(buf+6, packet+6, packet_len-6); | |
r = write(main_fd, buf, packet_len); | |
if (r < 0 && errno == EIO) { | |
fprintf(stderr, "Did you bring the tap device up?\n"); | |
break; | |
} | |
} | |
if (0){ | |
int flags = fcntl(main_fd, F_GETFL); | |
if (flags == -1) { PFATAL(""); } | |
r = fcntl(main_fd, F_SETFL, flags | O_NONBLOCK); | |
if (r == -1) { PFATAL(""); } | |
while (1) { | |
char buf[4096]; | |
r = read(main_fd, buf, sizeof(buf)); | |
if (r<0 || errno == EAGAIN) { | |
break; | |
} | |
if (r < 0) { | |
PFATAL("read"); | |
} | |
printf("got packet len=%d\n", r); | |
} | |
} | |
close(main_fd); | |
close(srv_fd); | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"Usage: flood_tun\n" | |
"\n" | |
"--iface INTERFACE Name of interface. Default: tap0\n" | |
"--src IP ADDRESS Specify source IP address\n" | |
"--dst IP ADDRESS Specify destination IP address\n" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <errno.h> | |
#include <linux/bpf.h> | |
#include <linux/tcp.h> | |
#include <netinet/in.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/socket.h> | |
#include <unistd.h> | |
#include <linux/filter.h> | |
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) | |
#define PFATAL(x...) \ | |
do { \ | |
fprintf(stderr, "[-] SYSTEM ERROR : " x); \ | |
fprintf(stderr, "\n\tLocation : %s(), %s:%u\n", __FUNCTION__, __FILE__, \ | |
__LINE__); \ | |
perror(" OS message "); \ | |
fprintf(stderr, "\n"); \ | |
exit(EXIT_FAILURE); \ | |
} while (0) | |
static int net_setup_bpf(int sd) | |
{ | |
struct sock_filter code[] = { | |
// ret #0 | |
{0x06, 0, 0, 0x00000000}, | |
}; | |
struct sock_fprog bpf = { | |
.len = ARRAY_SIZE(code), | |
.filter = code, | |
}; | |
int r = setsockopt(sd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)); | |
if (r < 0) { | |
PFATAL("setsockopt(SO_ATTACH_FILTER)"); | |
} | |
return sd; | |
} | |
int setup_server(struct sockaddr_storage *addr) | |
{ | |
int sd = socket(AF_INET, SOCK_STREAM, 0); | |
if (sd < 0) { | |
PFATAL("socket()"); | |
} | |
int r = bind(sd, (struct sockaddr *)addr, sizeof(*addr)); | |
if (r != 0) { | |
PFATAL("bind()"); | |
} | |
r = listen(sd, 16); | |
if (r != 0) { | |
PFATAL("listen()"); | |
} | |
socklen_t addr_sz = sizeof(*addr); | |
r = getsockname(sd, (struct sockaddr *)addr, &addr_sz); | |
if (r != 0) { | |
PFATAL("getsockname()"); | |
} | |
net_setup_bpf(sd); | |
return sd; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
set -e | |
NS=xxx | |
#gcc -Wall -Wextra flood_tun.c -o flood_tun | |
ip netns del ${NS} || true | |
ip netns add ${NS} | |
ip -n ${NS} link set lo up | |
ip -n ${NS} tuntap add mode tap multi_queue name tap0 | |
ip -n ${NS} link set dev tap0 up | |
#ip -n ${NS} -s link | |
ip -n ${NS} route add 10.111.112.0/24 dev tap0 | |
ip -n ${NS} neigh add 10.111.112.1 lladdr 70:71:aa:4b:29:aa dev tap0 | |
ip -n ${NS} route add 192.0.2.0/24 via 10.111.112.1 dev tap0 | |
ip -n ${NS} addr add 10.111.112.2 dev tap0 | |
# echo 1 | ip netns exec ${NS} tee /proc/sys/net/ipv4/ip_forward | |
# echo 1 | ip netns exec ${NS} tee /proc/sys/net/ipv4/conf/all/forwarding | |
ip netns exec ${NS} iptables -t raw -A PREROUTING -i tap+ -j CT | |
ip netns exec ${NS} iptables -t mangle -A PREROUTING -i tap+ | |
CTMAX=`cat /proc/sys/net/netfilter/nf_conntrack_max` | |
echo 4 | ip netns exec ${NS} tee /proc/sys/net/netfilter/nf_conntrack_max | |
ip netns exec ${NS} iptables -A INPUT -m conntrack --ctstate INVALID | |
ip netns exec ${NS} iptables -A INPUT -m conntrack --ctstate NEW | |
ip netns exec ${NS} iptables -A INPUT -m conntrack --ctstate ESTABLISHED | |
ip netns exec ${NS} iptables -A INPUT -m conntrack --ctstate RELATED | |
ip netns exec ${NS} iptables -A INPUT -m conntrack --ctstate UNTRACKED | |
ip netns exec ${NS} iptables -A INPUT | |
#ip netns exec ${NS} sysctl -w net.ipv4.conf.all.rp_filter=0 | |
#ip netns exec ${NS} sysctl -w net.ipv4.conf.tap0.rp_filter=0 | |
#ip netns exec ${NS} sysctl -w net.ipv4.conf.tap0.accept_local=1 | |
#ip netns exec ${NS} sysctl -w net.ipv4.conf.tap0.route_localnet=1 | |
ip netns exec ${NS} tcpdump -ni tap0 -B 16384 -ttt & | |
TCPDUMP_PID=$! | |
function finish_tcpdump { | |
kill ${TCPDUMP_PID} | |
ip netns del ${NS} | |
echo ${CTMAX} | tee /proc/sys/net/netfilter/nf_conntrack_max | |
echo | |
} | |
trap finish_tcpdump EXIT | |
sleep 0.3 | |
ip netns exec ${NS} ./flood_tun --src 192.0.2.8 --dst 10.111.112.2 | |
ip netns exec ${NS} conntrack -L | |
ip netns exec ${NS} iptables -t raw -L PREROUTING -v -x | |
ip netns exec ${NS} iptables -t mangle -L PREROUTING -v -x | |
#ip netns exec ${NS} iptables -L -v -x | |
#ip netns exec ${NS} cat /proc/net/ip_conntrack | |
# ip netns exec ${NS} iptables -t raw -L -v -x | |
# ip netns exec ${NS} iptables -t filter -L -v -x | |
# ip netns exec ${NS} iptables -t mangle -L -v -x | |
# ip netns exec ${NS} ss -n -a -t | |
# ip netns exec ${NS} cat /proc/sys/net/netfilter/nf_conntrack_max | |
#ip netns exec ${NS} bash | |
#ip -n ${NS} -s link | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <arpa/inet.h> | |
#include <errno.h> | |
#include <fcntl.h> | |
#include <getopt.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/resource.h> | |
#include <sys/stat.h> | |
#include <sys/time.h> | |
#include <unistd.h> | |
const char *optstring_from_long_options(const struct option *opt) | |
{ | |
static char optstring[256] = {0}; | |
char *osp = optstring; | |
for (; opt->name != NULL; opt++) { | |
if (opt->flag == 0 && opt->val > 0 && opt->val < 256) { | |
*osp++ = opt->val; | |
switch (opt->has_arg) { | |
case optional_argument: | |
*osp++ = ':'; | |
*osp++ = ':'; | |
break; | |
case required_argument: | |
*osp++ = ':'; | |
break; | |
} | |
} | |
} | |
*osp++ = '\0'; | |
if (osp - optstring >= (int)sizeof(optstring)) { | |
abort(); | |
} | |
return optstring; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment