#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <limits.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>

#define PACKETSIZE 96	//Точнее буфера

struct packet {
	struct tcphdr hdr;
	char buffer[PACKETSIZE];
};

int tcp_scan(struct addrinfo *addr);
uint16_t checksum(void *data, int length);

int main(int argc, char *argv[])
{
	struct addrinfo hints;
	struct addrinfo *result;
	int ret_getaddr;

	if (argc < 2) {
		fprintf(stderr, "Usage: %s host\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;
	hints.ai_flags = 0;

	ret_getaddr = getaddrinfo(argv[1], NULL, &hints, &result);
	if (ret_getaddr != 0) {
		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret_getaddr));
		exit(EXIT_FAILURE);
	}

	for (struct addrinfo *rp = result; rp != NULL; rp = rp->ai_next) {
		tcp_scan(rp);
	}

	exit(EXIT_SUCCESS);
}

uint16_t checksum(void *data, int length) {
	uint16_t *p = (uint16_t *) data;
	uint32_t sum;

	for (sum = 0; length > 1; length -= 2) {
		sum += *p++;
	}
	if (length == 1) {
		sum += *(uint8_t *) p;
	}

	sum = (sum >> 16) + (sum & 0xFFFF);
	sum += (sum >> 16);

	return ~sum;
}

int tcp_scan(struct addrinfo *addr) {
	struct packet pckt;
	int pcktlen = sizeof(struct packet);
	int tcp_socket;
	ssize_t ret_send, ret_recv;

	memset(&pckt, 0, sizeof(struct packet));
	pckt.hdr.th_sport = htons(rand() % (UINT16_MAX - 1024) + 1024);
	pckt.hdr.th_dport = htons(80);
	pckt.hdr.th_seq = rand() % UINT32_MAX;
	pckt.hdr.syn = 1;
	pckt.hdr.th_off = sizeof(struct tcphdr) / 4;
	pckt.hdr.th_win = PACKETSIZE;

	strcpy(pckt.buffer, "Hello, Example Domain!");

	pckt.hdr.th_sum = checksum(&pckt, pcktlen);

	tcp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
	if (tcp_socket == -1) {
		perror("tcp_socket");
		return 1;
	}

	ret_send = sendto(tcp_socket, &pckt, pcktlen, 0, addr->ai_addr, addr->ai_addrlen);
	if (ret_send == -1) {
		perror("sendto");
		return 1;
	}

	close(tcp_socket);
	
	return 0;
}