#include #include #include #include #include #include uint16_t checksum (uint16_t *, int); void make_and_send_synack( int sockfd, char *buf, int n, struct iphdr *ip, struct tcphdr *tcp, struct sockaddr *sin ); uint16_t tcp4_checksum (char *packet, struct iphdr *ip, struct tcphdr *tcp, int tcp_payload_len); int main(){ int sockfd, n; socklen_t clilen; const int on = 1; struct sockaddr_in cliaddr; char buf[IP_MAXPACKET]; int i; sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP); if (sockfd < 0){ perror("sock:"); exit(1); } // Set flag so socket expects us to provide IPv4 header. if (setsockopt (sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof (on)) < 0) { perror ("setsockopt() failed to set IP_HDRINCL "); exit (1); } clilen = sizeof(struct sockaddr_in); while(1){ printf(" before recvfrom\n"); n = recvfrom(sockfd, buf, 10000, 0, (struct sockaddr *)&cliaddr, &clilen); printf(" rec'd %d bytes\n",n); struct iphdr *ip_hdr = (struct iphdr *)buf; printf("IP header is %d bytes.\n", ip_hdr->ihl*4); for (i = 0; i < n; i++) { printf("%02X%s", (uint8_t)buf[i], (i + 1)%16 ? " " : "\n"); } printf("\n"); struct tcphdr *tcp_hdr = (struct tcphdr *)((char *)ip_hdr + (4 * ip_hdr->ihl)); // Make like a tiny tcpdump printf("TCP sport=%d, dport=%d ", ntohs(tcp_hdr->source), ntohs(tcp_hdr->dest)); if (tcp_hdr->syn && ! tcp_hdr->ack) printf("SYN"); else if( tcp_hdr->syn && tcp_hdr->ack ) printf("SYN+ACK"); else if( tcp_hdr->ack ) printf("ACK"); puts(""); if( tcp_hdr->syn ){ // respond with SYN+ACK make_and_send_synack( sockfd, buf, n, ip_hdr, tcp_hdr, (struct sockaddr*)&cliaddr); } } } void make_and_send_synack( int sockfd, char *buf, int n, struct iphdr *ip, struct tcphdr *tcp, struct sockaddr *sin ) { char res[IP_MAXPACKET]; memcpy(res, buf, n); struct iphdr *r_ip = (struct iphdr*) res; struct tcphdr *r_tcp = (struct tcphdr*) (res + 4*ip->ihl); r_ip->daddr = ip->saddr; r_ip->saddr = ip->daddr; r_tcp->source = tcp->dest; r_tcp->dest = tcp->source; r_tcp->ack_seq = htonl( ntohl(tcp->seq)+1 ); // all of this to just add 1 r_tcp->seq = htonl( 0xAAAABBBB ); r_tcp->ack = 1; r_tcp->check = 0; //recompute the checksums r_ip->check = checksum( (uint16_t *) res, 4 * ip->ihl); // pass by value here is weird, but we try... r_tcp->check = tcp4_checksum (res, r_ip, r_tcp, n - 4*ip->ihl - 4*tcp->doff); // Send packet. if (sendto (sockfd, res, n, 0, sin, sizeof (struct sockaddr_in)) < 0) { perror ("sendto() failed "); exit (1); } } // Build IPv4 TCP pseudo-header and call checksum function. // This could be done with zero copying, but it's left as an exercise // (or look it up in a TCP implementation). uint16_t tcp4_checksum (char *packet, struct iphdr *ip, struct tcphdr *tcp, int tcp_payload_len) { char buf[IP_MAXPACKET]; char *ptr; int chksumlen = 0; // ptr points to beginning of buffer buf ptr = &buf[0]; struct pseudo_tcp_header { in_addr_t saddr, daddr; u_char reserved; u_char protocol; u_short tcp_size; } ps_head; uint16_t header_len = 4*tcp->doff; ps_head.saddr = ip->saddr; ps_head.daddr = ip->daddr; ps_head.reserved = 0; ps_head.protocol = ip->protocol; ps_head.tcp_size = htons(header_len + tcp_payload_len); /* // Copy source IP address into buf (32 bits) memcpy (ptr, &ip->saddr, sizeof (in_addr_t)); ptr += sizeof (in_addr_t); // Copy destination IP address into buf (32 bits) memcpy (ptr, &ip->daddr, sizeof (in_addr_t)); ptr += sizeof (in_addr_t); // Copy reserved zero field to buf (8 bits) *ptr = 0; ptr++; // Copy transport layer protocol to buf (8 bits). That's IPPROTO_TCP. memcpy (ptr, &ip->protocol, sizeof (ip->protocol)); ptr += sizeof (ip->protocol); // Copy TCP length to buf (16 bits). That's header length + payload length int header_len = 4*tcp->doff; uint16_t svalue = htons(header_len + tcp_payload_len); memcpy (ptr, &svalue, sizeof (svalue)); ptr += sizeof (svalue); */ memcpy(ptr, &ps_head, sizeof(struct pseudo_tcp_header)); ptr += sizeof(struct pseudo_tcp_header); // now copy TCP header memcpy (ptr, tcp, header_len); // this must be result's TCP header! ptr += header_len; // ... and the TCP payload. memcpy (ptr, packet + ip->ihl*4 + header_len, tcp_payload_len); ptr += tcp_payload_len; chksumlen = ptr - buf; return checksum ((uint16_t *) buf, chksumlen); } // Computing the internet checksum (RFC 1071). uint16_t checksum (uint16_t *addr, int len) { int count = len; register uint32_t sum = 0; uint16_t answer = 0; // Sum up 2-byte values until none or only one byte left. while (count > 1) { sum += *(addr++); count -= 2; } // Add left-over byte, if any. if (count > 0) { sum += *(uint8_t *) addr; } // Fold 32-bit sum into 16 bits; we lose information by doing this, // increasing the chances of a collision. // sum = (lower 16 bits) + (upper 16 bits shifted right 16 bits) while (sum >> 16) { sum = (sum & 0xffff) + (sum >> 16); } // Checksum is one's compliment of sum. answer = ~sum; return (answer); }